# developer Genai - Full Documentation # Access Models API with Apex The Models API provides Apex classes that connect your application to large language models (LLMs). These Apex classes are autogenerated from the Models REST API specification using [External Services](https://help.salesforce.com/s/articleView?id=platform.external_services.htm). **note:** All Models API requests are subject to Salesforce’s usage and billing rates for Einstein Requests. See [Agentforce and Generative AI Usage and Billing](https://help.salesforce.com/s/articleView?id=ai.generative_ai_usage.htm) and the [Rate Card for Einstein Requests](https://www.salesforce.com/products/einstein/skus/). The Apex methods of the Models API are also subject to the Apex [Callout Limits and Limitations](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_callouts_timeouts.htm). ## Pick a Method The [ModelsAPI](/docs/ai/agentforce/references/models-apex-api/models-apex-reference.html#modelsapi) class in the `aiplatform` namespace provides a method for these generative AI capabilities. | Capability | Method Name | Description | | ------------------- | -------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | | Generate Chat | [`createChatGenerations`](/docs/ai/agentforce/references/models-apex-api/models-apex-reference.html#createchatgenerations) | Generate a response based on a list of messages representing a chat conversation. | | Generate Embeddings | [`createEmbeddings`](/docs/ai/agentforce/references/models-apex-api/models-apex-reference.html#createembeddings) | Create an embedding vector representing the input text. | | Generate Text | [`createGenerations`](/docs/ai/agentforce/references/models-apex-api/models-apex-reference.html#creategenerations) | Generate a response based on the prompt provided. | | Submit Feedback | [`submitFeedback`](/docs/ai/agentforce/references/models-apex-api/models-apex-reference.html#submitfeedback) | Submit feedback for generated text. | ## Choose a Model Each method, other than `submitFeedback`, requires the API name of the model as part of the request. For instance, if you want to use the OpenAI GPT-4o mini model for a generation request, specify the API name `sfdc_ai__DefaultOpenAIGPT4OmniMini` in the request. The Models API supports models from various Salesforce-enabled providers. See [Supported Models](https://developer.salesforce.com/docs/ai/agentforce/supported-models.md). ## Write Apex Code These examples demonstrate how to use Apex to communicate with the Models API. ### Generate Text To generate text, call the `ModelsAPI.createGenerations()` method with a prompt in your request body. If the request is successful, the response contains the generated text in the `Code200.generation.generatedText` field. If there’s an error, a `ModelsAPI.createGenerations_ResponseException` exception is thrown. ```apex // Create generate text request aiplatform.ModelsAPI.createGenerations_Request request = new aiplatform.ModelsAPI.createGenerations_Request(); // Specify model request.modelName = 'sfdc_ai__DefaultOpenAIGPT4OmniMini'; // Create request body aiplatform.ModelsAPI_GenerationRequest requestBody = new aiplatform.ModelsAPI_GenerationRequest(); request.body = requestBody; // Add prompt to body requestBody.prompt = 'Generate a welcome email for the new developer on the team, Jane Doe.'; try { // Make request aiplatform.ModelsAPI modelsAPI = new aiplatform.ModelsAPI(); aiplatform.ModelsAPI.createGenerations_Response response = modelsAPI.createGenerations(request); System.debug('Models API response: ' + response.Code200.generation.generatedText); // Handle error } catch(aiplatform.ModelsAPI.createGenerations_ResponseException e) { System.debug('Response code: ' + e.responseCode); System.debug('The following exception occurred: ' + e); } ``` ### Generate Chat To generate a chat message, call the [ModelsAPI.createChatGenerations](/docs/ai/agentforce/references/models-apex-api/models-apex-reference.html#createchatgenerations) method with a chronological list of chat messages in your request body. If the request is successful, the response contains the chat messages in the `Code200.generationDetails.generations` field. If there’s an error, a [ModelsAPI.createChatGenerations_ResponseException](/docs/ai/agentforce/references/models-apex-api/models-apex-reference.html#createchatgenerations_responseexception) exception is thrown. ```apex // Create generate chat request aiplatform.ModelsAPI.createChatGenerations_Request request = new aiplatform.ModelsAPI.createChatGenerations_Request(); // Specify model request.modelName = 'sfdc_ai__DefaultOpenAIGPT4OmniMini'; // Create request body aiplatform.ModelsAPI_ChatGenerationsRequest body = new aiplatform.ModelsAPI_ChatGenerationsRequest(); request.body = body; // Add chat messages to body List messagesList = new List (); aiplatform.ModelsAPI_ChatMessageRequest systemMessage = new aiplatform.ModelsAPI_ChatMessageRequest(); systemMessage.content = 'Make this request a little silly.'; systemMessage.role = 'system'; messagesList.add(systemMessage); aiplatform.ModelsAPI_ChatMessageRequest userMessage = new aiplatform.ModelsAPI_ChatMessageRequest(); userMessage.content = 'Can you give me a recipe for cherry pie?'; userMessage.role = 'user'; messagesList.add(userMessage); body.messages = messagesList; try { // Make request aiplatform.ModelsAPI modelsAPI = new aiplatform.ModelsAPI(); aiplatform.ModelsAPI.createChatGenerations_Response response = modelsAPI.createChatGenerations(request); System.debug('Models API response: ' + response.Code200.generationDetails.generations); // Handle error } catch(aiplatform.ModelsAPI.createChatGenerations_ResponseException e) { System.debug('Response code: ' + e.responseCode); System.debug('The following exception occurred: ' + e); } ``` ### Generate Embeddings To generate embeddings, call the [ModelsAPI.createEmbeddings](/docs/ai/agentforce/references/models-apex-api/models-apex-reference.html#createembeddings) method with the input text in your request body. If the request is successful, the response contains the embeddings vector in the `Code200.embeddings` field. If there’s an error, a [ModelsAPI.createEmbeddings_ResponseException](/docs/ai/agentforce/references/models-apex-api/models-apex-reference.html#createembeddings_responseexception) exception is thrown. ```apex // Create generate embeddings request aiplatform.ModelsAPI.createEmbeddings_Request request = new aiplatform.ModelsAPI.createEmbeddings_Request(); // Specify model request.modelName = 'sfdc_ai__DefaultOpenAITextEmbeddingAda_002'; // Create request body aiplatform.ModelsAPI_EmbeddingRequest body = new aiplatform.ModelsAPI_EmbeddingRequest(); request.body = body; // Add input to body List inputList = new List (); inputList.add('Every day, once a day, give yourself a present'); body.input = inputList; try { // Make request aiplatform.ModelsAPI modelsAPI = new aiplatform.ModelsAPI(); aiplatform.ModelsAPI.createEmbeddings_Response response = modelsAPI.createEmbeddings(request); System.debug('Models API response: ' + response.Code200.embeddings); // Handle error } catch(aiplatform.ModelsAPI.createEmbeddings_ResponseException e) { System.debug('Response code: ' + e.responseCode); System.debug('The following exception occurred: ' + e); } ``` ### Submit Feedback To submit feedback, call the [ModelsAPI.submitFeedback](/docs/ai/agentforce/references/models-apex-api/models-apex-reference.html#submitfeedback) method with feedback information in your request body. If there’s an error, a [ModelsAPI.submitFeedback_ResponseException](/docs/ai/agentforce/references/models-apex-api/models-apex-reference.html#createembeddings_responseexception) exception is thrown. ```apex // Create submit feedback request aiplatform.ModelsAPI.submitFeedback_Request request = new aiplatform.ModelsAPI.submitFeedback_Request(); // Provide feedback information in body aiplatform.ModelsAPI_FeedbackRequest feedbackRequest = new aiplatform.ModelsAPI_FeedbackRequest(); feedbackRequest.id = '78w60870345-2335840385-4857348-803483'; feedbackRequest.generationId = '89t608-46756v66y-23r4wqxe43-096mi'; feedbackRequest.feedback = 'GOOD'; feedbackRequest.feedbackText = 'The generation was helpful and did not require any changes'; feedbackRequest.source = 'HUMAN'; request.body = feedbackRequest; try { // Submit feedback aiplatform.ModelsAPI modelsAPI = new aiplatform.ModelsAPI(); aiplatform.ModelsAPI.submitFeedback_Response response = modelsAPI.submitFeedback(request); System.debug('Models API response: ' + response.Code202.message); // Handle error } catch(aiplatform.ModelsAPI.submitFeedback_ResponseException e) { System.debug('Response code: ' + e.responseCode); System.debug('The following exception occurred: ' + e); } ``` ## Test Your Apex These Apex classes are based on an [External Services](https://help.salesforce.com/s/articleView?id=platform.external_services.htm) framework. For guidance on testing your Apex, refer to the Apex Developer Guide, and information about External Services. - _Apex Developer Guide_: [Testing Apex](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_testing.htm) - _Salesforce Help_: [Testing External Services](https://help.salesforce.com/s/articleView?id=platform.external_services_test_actions_in_flow.htm) ## Next Steps To optimize your implementation, refer to these topics. - [Build Lightning Web Components and Flows with Models API](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api-build-lwc-flow.md) - [Supported Models](https://developer.salesforce.com/docs/ai/agentforce/supported-models.md) - [Rate Limits for Models API](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api-rate-limits.md) - [Models API Apex Reference](/docs/ai/agentforce/references/models-apex-api/models-apex-reference.html) - [Specify Languages and Locales with Models API](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api-languages-and-locales.md) ## See Also - _Salesforce Help_: [About Einstein Generative AI](https://help.salesforce.com/s/articleView?id=ai.generative_ai_about.htm) - _Models API Developer Guide_: [Access Models API with REST](https://developer.salesforce.com/docs/ai/agentforce/guide/access-models-api-with-rest.md) - _Apex Developer Guide_: [Getting Started with Apex](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_intro_get_started.htm) - _Trailhead_: [Get Started with the Models API](https://trailhead.salesforce.com/content/learn/modules/get-started-with-einstein-models-api) # Access Models API with REST The Models REST API connects your application to large language models (LLMs) for chat, embeddings, text generation, and feedback. Before you make a request, complete the shared authentication flow to create a Salesforce app and generate a JSON Web Token (JWT). See [Authenticate to the Models API](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api-authentication.md). Then use your token to call the endpoints described here. **note:** All Models API requests are subject to Salesforce’s usage and billing rates for Einstein Requests. See [Agentforce and Generative AI Usage and Billing](https://help.salesforce.com/s/articleView?id=ai.generative_ai_usage.htm) and the [Rate Card for Einstein Requests](https://www.salesforce.com/products/einstein/skus/). ## Postman Collection The quickest way to get started with the Models REST API is with our [Postman collection](https://www.postman.com/salesforce-developers/workspace/salesforce-developers/collection/12721794-582bb775-b99d-46d8-88cf-df0d3a341040). ## Call the Models REST API When you have a valid token, you can call any of the Models REST API endpoints. ### Pick a Capability The Models REST API provides four different endpoints for four different capabilities. | Capability | Endpoint Path | Description | | ------------------- | ---------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | | Generate Chat | [`/models/{modelName}/chat-generations`](/docs/ai/agentforce/references/models-api#operation/generateChat) | Generate a response based on a list of messages representing a chat conversation. | | Generate Embeddings | [`/models/{modelName}/embeddings`](/docs/ai/agentforce/references/models-api#operation/generateEmbeddings) | Create an embedding vector representing the input text. | | Generate Text | [`/models/{modelName}/generations`](/docs/ai/agentforce/references/models-api#operation/generateText) | Generate a response based on the prompt provided. | | Submit Feedback | [`/feedback`](/docs/ai/agentforce/references/models-api#operation/submitFeedback) | Submit feedback for generated text. | ### Choose a Model Choose a model to use when you call the generations or embeddings endpoints. Each endpoint, other than the feedback endpoint, requires the API name of the model as part of the path. For instance, if you want to use the OpenAI GPT-4o mini model for a generation request, specify the API name `sfdc_ai__DefaultOpenAIGPT4OmniMini` by making a request to this endpoint. ```bash https://api.salesforce.com/einstein/platform/v1/models/sfdc_ai__DefaultOpenAIGPT4OmniMini/generations ``` The Models API supports models from various Salesforce-enabled providers. See [Supported Models](https://developer.salesforce.com/docs/ai/agentforce/supported-models.md). ### Provide Headers These headers are relevant for API requests. | Header | Description | Example | | --------------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------------- | | `Authorization` | Required. Authorization method for this request. This header must contain your JWT. | `Bearer {token}` | | `Content-Type` | Required. Specify the `application/json` content type. | `application/json` | | `x-sfdc-app-context` | Required. This value is reserved for future use. For now, specify `EinsteinGPT`. | `EinsteinGPT` | | `x-client-feature-id` | Required. This value is reserved for future use. For now, specify `ai-platform-models-connected-app`. | `ai-platform-models-connected-app` | ### Make a Request Make a POST request to one of [the Models REST API endpoints](/docs/ai/agentforce/references/models-api?meta=summary). This example demonstrates a call to the `generations` endpoint. ```bash curl --location 'https://api.salesforce.com/einstein/platform/v1/models/sfdc_ai__DefaultOpenAIGPT4OmniMini/generations' \ --header 'Authorization: Bearer ••••••' \ --header 'Content-Type: application/json' \ --header 'x-sfdc-app-context: EinsteinGPT' \ --header 'x-client-feature-id: ai-platform-models-connected-app' \ --data '{ "prompt": "James Lee is a financial advisor, living in San Diego. His phone number is 867-5309. Generate a story about his work and life." }' ``` **tip:** If you receive a `401` or `404` response code, verify that your Salesforce app includes all the required scopes and settings, and that you're using the complete `access_token` value that you generated. See [Authenticate to the Models API](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api-authentication.md). And here’s a sample response. ```json { "id": "chatcmpl-9AMuFltdq7M5ntZVvQcAkgyWhfoas", "generation": { "id": "333127bd-2d5d-41e8-9781-59a1a18ed69f", "generatedText": "Once upon a time in sunny San Diego, there lived a diligent and experienced financial advisor named James Lee. With a passion for numbers and a knack for helping others achieve their financial goals, James had built a reputation as a trusted advisor in the community.\n\nJames had always been fascinated by the world of finance. From a young age, he would spend hours poring over financial newspapers and studying the stock market. As he grew older, his passion only intensified, leading him to pursue a degree in finance from a prestigious university...", "contentQuality": { "scanToxicity": { "isDetected": false, "categories": [ { "categoryName": "identity", "score": 2.0e-5, }, { "categoryName": "hate", "score": 0.0, }, { "categoryName": "profanity", "score": 3.0e-5, }, { "categoryName": "violence", "score": 2.0e-5, }, { "categoryName": "sexual", "score": 1.5e-4, }, { "categoryName": "physical", "score": 0.0, } ] } }, "parameters": { "finish_reason": "stop", "index": 0, "logprobs": null } }, "moreGenerations": null, "prompt": null, "parameters": { "created": 1712258359, "usage": { "completion_tokens": 607, "prompt_tokens": 39, "total_tokens": 646 }, "model": "gpt-35-turbo", "system_fingerprint": null, "object": "chat.completion" } } ``` ## Next Steps After you successfully call the API, refer to these topics to optimize your implementation. - [Supported Models](https://developer.salesforce.com/docs/ai/agentforce/supported-models.md) - [Rate Limits for Models API](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api-rate-limits.md) - [Specify Languages and Locales with Models API](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api-languages-and-locales.md) - [Toxicity Scoring with Models API](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api-toxicity-scoring.md) - [Data Masking with Models API](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api-data-masking.md) - [Get Generation Feedback Using Models API](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api-feedback.md) - [Access Models API with Apex](https://developer.salesforce.com/docs/ai/agentforce/guide/access-models-api-with-apex.md) - [Build Lightning Web Components and Flows with Models API](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api-build-lwc-flow.md) - [Models REST API Reference](/docs/ai/agentforce/references/models-api?meta=summary) ## See Also - _Salesforce Help_: [Agentforce and Einstein Generative AI](https://help.salesforce.com/s/articleView?id=ai.generative_ai.htm) - _Salesforce Help_: [External Client Apps](https://help.salesforce.com/s/articleView?id=xcloud.external_client_apps.htm) # Access Predictive Endpoints with REST The predictive endpoints of the Models API are REST-only. Authenticate with the same JWT flow used by the generative endpoints, then `POST` to the predictive endpoint for the capability you need. ## Authenticate Predictive endpoints use the same JWT authentication flow as the generative REST endpoints. To create an external client app, generate a JWT, and set up your authorization header, see [Authenticate to the Models API](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api-authentication.md). ## Call a Predictive Endpoint Predictive endpoints follow this shape: ``` POST /einstein/platform/v1/models/{modelApiName}/{method} ``` Where `{method}` is one of: | Capability | Endpoint Path | Predicts | | -------------------- | ----------------------- | --------------------------------- | | Regression | `/regression` | A continuous numeric value. | | Forecast | `/forecast` | Future values of a time series. | | Classification | `/classification` | A probability per class. | | Multi-Outcome | `/multi-outcome` | Several outcomes for each record. | | Topic Classification | `/topic-classification` | Caller-supplied topics for texts. | | Sentiment Detection | `/sentiment-detection` | Sentiment for a batch of texts. | ## See Also - [Predict with Models API](https://developer.salesforce.com/docs/ai/agentforce/guide/predict-with-models-api.md) - [Access Models API with REST](https://developer.salesforce.com/docs/ai/agentforce/guide/access-models-api-with-rest.md) # Add Custom Evaluation Criteria to a Test Case To test an agent response for specific strings or numbers, you can create custom evaluations. This enables you to create test cases for any data in an agent response, extending testing capabilities beyond standard or out-of-the-box expectations. Custom evaluations enable more specific testing, such as ensuring that latency is less than 10 seconds, or that agent action inputs and outputs meet certain requirements. ## Get Started with Custom Evaluation Criteria Custom evaluations follow a different format from standard expectations. Instead of defining an expectation with a name and an expected value, custom evaluations require individual parameters to define the evaluation requirements. Currently, there are two different types of custom evaluations that you can add to your test metadata. - **String comparison**: Tests a response for a specific string value. The API name for this evaluation is `string_comparison`. - **Numeric comparison**: Tests a response for a specific numeric value. The API name for this evaluation is `numeric_comparison`. ## Use Parameters to Define a Custom Evaluation This example custom evaluation checks if the reply email created by the DraftGenericReplyEmail action mentions the right person. ``` string_comparison operator equals false actual $.generatedData.invokedActions[*][?(@.function.name == 'DraftGenericReplyEmail')].function.input.recipient true expected Jon false ``` This example of a custom evaluation has three different parameters: an actual value, an expected value, and an operator to compare them. Each parameter is defined with a `name` field, a `value` field, and an `isReference` field. The parameters are set individually using the `AiEvaluationExpectationParameter` format. For details, see the [Metadata reference](/docs/ai/agentforce/references/testing-api/testing-metadata-reference.html). This example evaluation uses the `equals` operator. This means the test case checks if the `actual` value from the agent matches the `expected` value. All string comparison operators are case sensitive. There are different valid operators for string comparison and numeric comparison evaluations. The valid string comparison operators are: - `equals`: Checks if the `actual` value directly matches the `expected` value. - `contains`: Checks if the `actual` value contains the `expected` value. - `startswith`: Checks if the `actual` value begins with the `expected` value. - `endswith`: Checks if the `actual` value ends with the `expected` value. The valid numeric comparison operators are: - `equals`: Checks for numerical equality. - `greater_than_or_equal`: Checks if the `actual` value is greater than or equal to (`>=`) the `expected` value. - `greater_than`: Checks if the `actual` value is greater than (`>`) the `expected` value. - `less_than`: Checks if the `actual` value is less than (`<`) the `expected` value. - `less_than_or_equal`: Checks if the `actual` value is less than or equal to (`<=`) the `expected` value. **note:** Each parameter field is limited to 100 characters. The actual value is retrieved with a JSONPath expression. This expression enables you to automatically point to the data you want to test from the [Get Test Results](/docs/ai/agentforce/references/testing-api/testing-connect-reference.html#get-test-results) resource in Connect API. For details on how to construct a JSONPath expression, see [Dynamically Reference Generated Data](#dynamically-reference-generated-data). ### Dynamically Reference Generated Data In most custom evaluations, the `value` for the `actual` result is a JSONPath expression that points to generated data. This is runtime data from the `generatedData` object returned by the [Get Test Results](/docs/ai/agentforce/references/testing-api/testing-connect-reference.html#get-test-results) resource. For this expression to dynamically reference data, `isReference` must be set to `true`. Most JSONPath expressions for custom evaluations follow a pattern. ``` $.generatedData.invokedActions[*][?(@.function.name == '{ACTION}')].{DYNAMIC_DATA} ``` You can show the generated JSON data when retrieving test results via Agentforce DX. To show the generated JSON, add the `--verbose` flag to a `agent test run` command. For more information, see [Customize the Agent Test Spec](https://developer.salesforce.com/docs/ai/agentforce/agent-dx/agent-dx-test-customize.md). #### Example JSONPath Expressions Get the `query` input for the `namespace_actionName` action: ``` $.generatedData.invokedActions[*][?(@.function.name == {namespace_actionName})] .function.input.query ``` Get the `result` output for the `namespace_actionName` action: ``` $.generatedData.invokedActions[*][?(@.function.name == 'namespace_actionName')] .function.output.result ``` Get the `value` from the first `additionalContext` item for the `namespace_actionName` action: ``` $.generatedData.invokedActions[*][?(@.function.name == {namespace_actionName})] .function.output.additionalContext[0].value ``` For information on JSONPath operators, see the [official documentation](https://javadoc.io/doc/com.jayway.jsonpath/json-path/2.2.0/com/jayway/jsonpath/JsonPath.html). ## Example Test Case Definition This is a complete test case metadata file that demonstrates standard expectations, out-of-the-box metrics, custom evaluation criteria, and context variables. ``` My first Salesforce Agent test Agent_Sanity AGENT Sales_Agent v1 1 Summarize the Global Media account OrchestrationStage 001SB00000MC0yrYAD_test EndUserLanguage Spanish topic_sequence_match OOTBSingleRecordSummary action_sequence_match ['IdentifyRecordByName', 'SummarizeRecord'] bot_response_rating Summarization of the Global Media account including important points coherence output_latency_milliseconds 2 List contact names associated with Global Media account topic_sequence_match GeneralCRM action_sequence_match ['IdentifyRecordByName', 'QueryRecords'] bot_response_rating should respond with list of contacts string_comparison operator equals false actual $.generatedData.invokedActions[*][?(@.function.name == 'DraftGenericReplyEmail')].function.input.recipient true expected Jon false ``` # ADL Agent Example - Demystify Jargon with Knowledge Ensure that your [grounded](https://help.salesforce.com/s/articleView?id=ai.agent_parent_data.htm&type=5) agent understands your organization's evolving jargon, domain-specific terms, or updated product names — without having to update and reindex your information sources. ## The Problem Grounded agents are grounded in information, either using an [Agentforce Data Library](https://help.salesforce.com/s/articleView?id=ai.data_library_parent.htm&type=5) or [Retrieval Augmented Generation](https://help.salesforce.com/s/articleView?id=ai.generative_ai_rag.htm&language=en_US&type=5). However, the grounding information might contain only formal names while customers use jargon, acronyms, or new names. Even if the grounding information contains both correct and jargon terms, it might be [indexed](https://help.salesforce.com/s/articleView?id=data.c360_a_search_index_manage.htm&type=5) only on the correct names — so the retriever or data library misses relevant chunks even though correct information exists. Updating and reindexing an agent's grounding information (which typically contains thousands of articles) can be time-consuming and involve special roles. Plus, jargon can change quickly! ## The Solution One solution is to map informal to correct terms before retrieval. Maintain a lightweight old-to-new term map in Salesforce Knowledge (or other object), fetch the mapped information once per session, and hydrate the prompt so the agent can translate user questions when necessary. By telling your agent to map jargon to correct terms before fetching grounding content, your agent can find relevant chunks in the search index and reduce false “irrelevant question” routing. By using Knowledge (or other object), business users rather than IT can make terminology updates. ### When to Map Terms Before Retrieval This solution is a good fit when: - Your grounding content is mostly correct, but users ask questions with terms that differ from your indexed content. - Product names, acronyms, or internal jargon change frequently, but the core content in your data library is still accurate. - Your terminology map isn't so large that it impacts your agent's [context engineering](https://help.salesforce.com/s/articleView?id=ai.agent_context_engineering.htm). ### When Not to Use This Solution This solution is **not** a good fit when: - Your terminology map is so large it starts to affect your agent's performance. - Your information sources are easy to update and re-index. ## Set up A Salesforce Developer Org To follow along with this example, you can sign up for a free Salesforce Developer Edition org, then configure the org with Data Cloud and Agentforce. **note:** Instead of signing up for a new org, you can re-use an existing developer org. For a complete Agentforce implementation guide, see [Create Agents in Record Time with Agentforce Implementation Guides](https://help.salesforce.com/s/articleView?id=ai.agent_resources.htm&type=5). ### Sign Up for a Developer Org 1. Go to the [signup page](https://www.salesforce.com/form/developer-signup/?d=pb) to sign up for a Developer Edition org with Agentforce and Data Cloud. 2. Fill out the form and submit it. 3. Look for a welcome email from Salesforce in your inbox. 4. Verify your account using the verification link in the email. 5. When prompted, set a new password and select a security question for your Developer Edition org. Then complete the login process. 6. Keep track of your username and password so that you can log in again later from the Salesforce [login page](http://login.salesforce.com). ### Verify Data Cloud in Your Org Data Cloud is required for essential Einstein generative AI and Agentforce functionality, such as the Trust Layer, agent event logs, and consumption billing tracking. In our example, we need Data Cloud for Agentforce Data Library. Verify your Data Cloud installation. From Setup, in the Quick Find box, enter **Data Cloud**, and then select **Data Cloud Setup Home**. Verify that a home org is created on the Data Cloud Setup Home page, with a home org ID, a home org instance, and a tenant endpoint. If Data Cloud isn't set up, in Set Up Data Cloud, click **Get Started**. Setup can take about 10 minutes. ### Enable Einstein Generative AI Turn on Einstein to use generative AI features, including Agentforce. 1. From Setup, in the Quick Find box, enter `Einstein Setup`, and then select **Einstein Setup**. 2. Enable **Turn on Einstein**. 3. Refresh the page. After you turn on Einstein, it can take a few minutes to sync Einstein and Data Cloud. ### Enable Agentforce Turn on Agentforce to start building, customizing, testing, and launching AI agents. 1. From Setup, in the Quick Find box, enter Agent, and then select **Agentforce Agents**. If you don’t see Agents in Setup, verify that Einstein Generative AI is enabled for your org. 2. To enable Agentforce, turn on **Agentforce**. After you enable Agentforce, refresh the page to see the New Agentforce Builder panel. ## Create Your Agent Use the standard Agentforce Service Agent template. ### Aura & Ash's Business Challenge Aura & Ash sells skincare products and has a service agent that helps customers select, combine, and use products. Because product names frequently change, and the company wants to stay current with viral product nicknames, Aura & Ash will create a Knowledge article to map old and new product names. ### Create a Default Service Agent 1. In the New Agentforce Builder panel, click **Let's Go**. To access the Agentforce Builder later, from the App Launcher, find and select **Agentforce Studio**, and then click **Agents**. 2. Click **New Agent**, then select **Agentforce Service Agent**. 3. Name your agent `Aura & Ash Service Agent` and accept the developer default. 4. Click **Select User**, then select `EinsteinServiceAgent` user. 5. Click **Let's Go**. The agent opens in canvas view. You can see that the Service Agent template provides typical subagents for a service agent. Leave your new agent open in a browser tab. ## Create Your Data Library To ground your agent’s responses in Aura & Ash's product information, you'll create a [data library](https://help.salesforce.com/s/articleView?id=ai.data_library_parent.htm&type=5) and upload a PDF. 1. Download the [Aura_Ash_Product_Instructions.pdf](https://resources.docs.salesforce.com/rel1/doc/en-us/static/pdf/Aura_Ash_Product_Instructions.pdf). This PDF provides brief usage instructions for skincare products, but uses the old product names. 2. Leave your agent open in a browser tab. From Setup, in the Quick Find box, enter `Data Library`, and then select **Agentforce Data Library**. 3. Click **New Library**. 4. For the library name, enter `Aura and Ash Products`. The API name is automatically populated. 5. For the description, enter `Sources for Aura & Ash Customer Service agent’s product usage agent`. 6. Save your changes. 7. In the Data Type field, select **Files**. 8. Click **Select Files**, then upload the `Aura & Ash Product Instructions.pdf` file from wherever you saved it on your computer. When your file is finished uploading, click **Done**. Salesforce takes some time to create your data library. Wait until the Status is `Ready` — you might need to refresh your page. ![ADL ready](https://developer.salesforce.com/media/agent-script/rag-example/ADL_ready.png) ### Assign Your Data Library to the Agent Now that you’ve created your data library, add it to your agent. 1. From your agent's Explorer panel, expand **Data** and select **Data Library**. 2. Select the **Aura & Ash Products** library. If you don’t see your library, refresh the page. 3. Leave the Show Sources setting disabled. When this setting is enabled, your agent shows the sources for every answer it generates with your data library. For the Aura & Ash use case, we'll leave that setting disabled because we’re using a single PDF for all answers. 4. In the upper right, click **Save**. ### Test Your Agent Your agent is now grounded on Aura & Ash product instructions and can answer customer questions, provided customers use legacy product names. 1. Click **Preview** and click **Refresh** (circular arrow). 2. In the test window, enter this text: `How do I use the Hand & Cuticle Oil`. 3. The agent responds with information grounded in your library, such as massaging a few drops into your nails and allowing time for absorption. 4. Now, repeat the question with the product's new name by entering `How do I use Iron Grip Rescue Fuel?`. The agent doesn't have your product's new name and responds that it can't help. We'll download the product's old and new name map in the next step, so that the agent can find the relevant information. **note:** By testing the agent with new terms before you map them, you're ensuring that your agent doesn't already know your new terms. Sometimes, jargon or domain-specific knowledge is still part of the public knowledge set on which the LLM was trained. In that case, the LLM might correctly link a customer's jargon term to your data library's knowledge without using your terminology map. It's important to verify a failure case first, so you can validate your solution later. ## Create a Terminology Map with Salesforce Knowledge Your agent is grounded on Aura & Ash's product usage information, but your data library uses the old product names. Real-world data libraries can be large and complex to configure. It's often much easier to provide an agent with a simple terminology map that a business user can update, rather than rewriting and rebuilding a data library. ## Set up Salesforce Knowledge To create a Knowledge article, set up Salesforce Knowledge, grant yourself and your agent user permissions on the `knowledge__kav` object, create a template, and grant the agent user access to Knowledge. **note:** This example walks you through a basic Knowledge setup that meets the needs of this example. If your organization already uses Knowledge, you can use an existing article type. ### Assign Yourself the Knowledge User License Assign your user the Knowledge user license so you can create Knowledge articles. 1. From **Setup**, in the Quick Find box, enter and select **Users**. 1. Next to your user name, click **Edit**. 1. Select the **Knowledge User** checkbox. 1. Click **Save**. ### Enable Salesforce Knowledge 1. From **Setup**, in the Quick Find box, enter and select **Knowledge Settings**. 2. Select **Yes, I understand the impact of enabling Salesforce Knowledge** and click **Enable Salesforce Lightning Knowledge**, then click **Ok**. ### Create a New Article Layout You need a Knowledge article layout with a text field to hold your map of old and new product names. **note:** This example adds a custom field to the Knowledge layout. If your organization already has layouts defined, consider reusing an existing layout. 1. In Setup, select **Object Manager**. 2. In Quick Find, enter and select **Knowledge** (API name `Knowledge__kav`). 3. Select **Fields & Relationships** then click **New**. 4. Select **Text Area** (Long) and click **Next**. 5. Enter this information: | Field | Value | | :---- | :---- | | Field Label | `Alternate Product Names` | | Description | `New or alternate names, acronyms, and slang terms for products`| | Visible lines| `40` | | Field Name | Accept `Alternate_Product_Names__c`| 6. Leave all other fields the same and click **Next**. 7. Ensure the new field is visible to the Einstein Agent User and click **Next**. 8. Select the box next to **Knowledge Layout** and click **Save**. The new field is created and added to the Knowledge page layout. ### Grant Your Agent Permissions to `Knowledge__kav` Your agent user needs read permissions on the Knowledge object,`Knowledge__kav`, but only when operating the Aura & Ash agent. 1. From **Setup**, in the Quick Find box, enter and select **Permission Sets**. 2. Click to open the **Agentforce Agent Aura_Ash_Service_Agent** Permission set. 3. Click to open **Object Settings**. 4. Scroll down, then click to open **Knowledge**, with the API name `Knowledge__kav`. 5. Click **Edit**. 6. Under Object Permissions, for Read and View all Fields, select **Enabled**. 7. Click **Save**. ![ADL ready](https://developer.salesforce.com/media/agent-script/rag-example/agent_perms.png) **note:** Always give your agent user the fewest permissions it needs to do its job. In this example, our EinsteinServiceAgent user doesn't need write access. For more information about service agent permissions, see [(Help:) Best Practices for Agent User Permissions](https://help.salesforce.com/s/articleView?id=ai.agent_user.htm&type=5). ### Give Your Agent User Access to Knowledge You can't give the agent user a Knowledge license, but you can grant the Allow View Knowledge app permission. 1. From **Setup**, in the Quick Find box, enter and select **Users**. 2. Click to open your EinsteinServiceAgent name. 3. Expand the list of permission set assignments, then click to open the **Service User** permission set. 4. Click to open **App Permissions**. 5. Click **Edit**. 6. Select **Allow View Knowledge**. 7. Click **Save**. Your agent user has permissions to view Knowledge articles. For more information about agent user permissions, see [(_Help_):Best Practices for Agent User Permissions](https://help.salesforce.com/s/articleView?id=ai.agent_user.htm&type=5). ### Create a Knowledge Article 1. Download the document [Aura_Ash_New_Names.pdf](https://resources.docs.salesforce.com/rel1/doc/en-us/static/pdf/Aura_Ash_New_Names.pdf). This document maps old product names to new product names. 2. From the app menu, enter and select **Knowledge**, then click **New** to create a new Knowledge document. 3. Name your document `Aura & Ash Updated Product Names` and accept the default URL name. 4. In the field Alternate Product Names, paste the entire contents of the `Aura & Ash New Names.pdf`, including the instructions. ![script added](https://developer.salesforce.com/media/agent-script/rag-example/new_knowledge.png) 5. Click **Save**. 6. Return to the list of Knowledge articles, then select and publish your article. 7. Copy your Knowledge article number - you'll need it to create your agent action. ![script added](https://developer.salesforce.com/media/agent-script/rag-example/article_number.png) Your Knowledge Article is published and ready to use in a Flow. ## Create a Flow to Fetch the Knowledge Article Create a flow that looks up your knowledge article by article ID. 1. From Setup, in the Quick Find box, enter **Flows**, and then select **Flows**. 2. Click **New Flow**. 3. Select the **Autolaunched Automations** category, and then select **Autolaunched Flow (No Trigger)**. 4. Add a Get Records Element. 1. For the label, enter `Get Knowledge Article by ID.` 2. For the object, select **Knowledge** (**Knowledge\_\_kav)**. 5. Select the knowledge record by article number - For the condition requirements, leave **All Conditions Are Met (And)** selected. - For the field, select **Article Number**. - For the operator, select **Equals**. - For the value, add a new resource with these values: | Field | Value | | :---------------------------- | :------------------ | | Resource Type | Variable | | API Name (case-sensitive) | articleNumber | | Description | The article number | | Data Type | Text | | Availability Outside the Flow | Available for input | 6. Click **Done** 7. Create a variable to store the new product names. - Under How to Store Record Data, select **Choose fields and assign variables (advanced)**. - Under Where to Store Field Values, select **In separate variables**. - Under Select Variables to Store Knowledge Fields, for Field, select **Alternate_Product_Names\_\_c**. - For Variable, create a new resource. | Field | Value | | :---------------------------- | :------------------------------------------- | | Resource Type | Variable | | API Name (case-sensitive) | alternateProductNames | | Description | List of products with their alternate names. | | Data Type | Text | | Default Value | leave blank | | Availability Outside the Flow | Available for output | 1. Click **Done**. 2. Select **When no records are returned, set specified variables to null**. 3. Save the flow. Use the name `Alternate Product Names` and accept the api name. ### Test Your Flow To test your flow and make sure your agent has all of the required permissions to run it, debug the flow as your agent user. 1. Give yourself permission to debug your flow as another user. - From Setup, in the Quick Find box, enter `Process Automation`, and then select **Process Automation Settings**. - Select **Let admins debug flows as other users** then click **Save**. 2. In Flow Builder, click **Debug**. - Select **Run automation as another user**, and then select your EinsteinServiceAgent User. - For articleNumber, enter the article number for your Aura & Ash Updated Product Names article. You saved this number in a previous step. - Click **Run** and expand Details to see the returned list of product names. 3. To activate the flow, click **Activate**. **Tip**: If you get an error running the flow as the EinsteinServiceAgent user, switch to your user. If the flow is successful running under your user, check the EinsteinServiceAgent's permissions. ## Update Your Agent to Fetch and Store the Mapped Product Names Now that you've created a Knowledge article to map old and new product names, then created a flow to fetch the names, you're ready to ground your agent with the new product names. First, you'll create a variable to store the mapped names. Then, you'll create an agent action based on your flow. Finally, you'll update your agent to run the action and use the mapped names to find answers to your customer's questions. ### Create the Old2NewProductNames Variable You'll use the Old2NewProductNames variable to store the mapped product names that your flow returns from the Knowledge article. 1. In your agent's Explorer panel, click **Variables**. 2. In the upper right of the Canvas, click **New**, then select **Create Custom Variable**. 3. Use these values to create your variable. | Field | Value | |-----------------|-----------------------------------------------------| | Name and API Name | Old2NewProductNames | | Data Type | String | | Description | Maps the old product names to the new product names. | | Default value | NotRun | 4. Click **Create**, then save your agent. Your **Old2NewProductNames** variable is created. ### Create the GetNewProductNames Action 1. In Agentforce Builder, from the Explorer tab, expand **Subagents** \> **General FAQ.** 2. Click the **plus sign** **(+)** next to General FAQ and select **Create New Action**. 3. Set these fields on your action. | Field | Value | |---------------|-------------------------------| | Action Name | GetNewProductNames | | Description | Get the new names for products.| 4. Click **Create and Open**. 5. For the reference action type, select **Flow**. 6. For the reference action, select your **Alternate Product Names** flow. 7. Under Inputs, for articleNumber, select **Require Input to execute action**. 8. Under Outputs, for alternateProductNames, select **Show in conversation**. 9. Click **Save**. ### Deterministically Run the GetNewProductNames Action Run your GetNewProductNames action in the reasoning instructions, then store the output list of mapped names in the Old2NewProductNames variable. To improve performance, only run the action once by checking if the Old2NewProductNames variable is `NotRun`. 1. Switch to Script mode. 2. In the GeneralFaq subagent, below `instructions: ->` and above `| Your job is solely to help with issues`, paste these instructions. ```agentscript if @variables.Old2NewProductNames == "NotRun": run @actions.GetNewProductNames with articleNumber = "000001000" set @variables.Old2NewProductNames = @outputs.alternateProductNames ``` 3. Align the script with the pipe ("`|`") character below. 4. If needed, replace **000001000** with your Knowledge article's article number that you copied in a previous step. Your script should look like this. ![script added](https://developer.salesforce.com/media/agent-script/rag-example/action_script.png) 5. Save the agent, then verify in Canvas view. ![script added](https://developer.salesforce.com/media/agent-script/rag-example/action_script_canvas.png) ### Instruct the Agent to Consider New Product Names 1. In Canvas, click your cursor after the first sentence, which says something like `Your job is solely to help with issues and answer questions about the company's products, procedures, or policies by searching knowledge articles.` 2. Press **Enter/Return**, then paste this text. `Product names have changed. Customers might use a new product name in their questions. When a mentioned product is not found in the knowledge content, consult` 3. Enter `"@"` to bring up the context menu, then scroll down to **This Agent's Variables** and select **Old2NewProductNames**. 4. Paste this text `to determine whether it maps to an older product name. If a mapping exists, use the older product name when searching knowledge articles.` 5. Click **Save**. Your Canvas view should look like this. ![canvas view](https://developer.salesforce.com/media/agent-script/rag-example/variable_canvas_view.png) ## Test Your Agent Your agent is now grounded on Aura & Ash product instructions and new product names. The agent can answer customer questions for both legacy and new product names. 1. Click **Preview**, then next to **Set Context**, click **Refresh** (circular arrow). 2. Enter the prompt: `Tell me about the Iron Grip Rescue Fuel`. 3. The agent responds with information grounded in your library for the old product name, Hand & Cuticle Oil. You can see that your Get Alternate Product Names action is run only once. ![Final query](https://developer.salesforce.com/media/agent-script/rag-example/final_utterance.png) ## More Information This example's Agent Script uses these [patterns and best practices](https://developer.salesforce.com/docs/ai/agentforce/agent-script/patterns/ascript-patterns.md). | Pattern | Usage in Script | | -------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Fetch Data Before Reasoning](https://developer.salesforce.com/docs/ai/agentforce/agent-script/patterns/ascript-patterns-fetch-data.md) | The flow runs **before** the prompt is sent to the LLM, so the agent always has our updated product names. | | [Using Conditionals](https://developer.salesforce.com/docs/ai/agentforce/agent-script/patterns/ascript-patterns-conditionals.md) | The `if @variables.Old2NewProductNames == "NotRun"` check ensures the action is run only once, reducing processing and potentially cost. | | [Using Variables Effectively](https://developer.salesforce.com/docs/ai/agentforce/agent-script/patterns/ascript-patterns-variables.md) | `Old2NewProductNames` has a default value, so we can check when it's not been used. | | Verify the agent with a known failure case | LLMs can infer a surprising amount of information and have been trained on a vast array of public knowledge. Before injecting the prompt with our product name map, we verified the agent didn't understand the new product names. That way, we're confident that the updated name information is coming from our map, not from inference or public knowledge. | Agent API # Agent API Use Agent API to communicate with AI agents in your org. Get access to your topics and actions in Agentforce by sending messages to AI agents. Create a Salesforce app in your org, generate a token, and then start using the API. To onboard to this API, see [Get Started with the Agent API](/docs/ai/agentforce/guide/agent-api-get-started.html) and [Agent API Examples](/docs/ai/agentforce/guide/agent-api-examples.html). ### Postman Collection The quickest way to get started with the Agent API is with our [Postman collection](https://www.postman.com/salesforce-developers/salesforce-developers/collection/gwv9bjy/agent-api). ### Endpoints * [Start a Session](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=startSession): Start a session with an agent. * [Send a Message (sync)](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=sendMessage): Send a sync message to the agent on an active session. * [Send a Message (streaming)](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=sendMessageStream): Send a streaming message to the agent on an active session. * [End a Session](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=endSession): End a session. * [Submit Feedback](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=submitFeedback): Submit feedback for a message. **Version:** v1.0.0 ## Servers * `https://api.salesforce.com/einstein/ai-agent/v1` Agent API - Production Environment ## Security * `jwtBearer` (http) Salesforce OAuth access token obtained using the JWT Bearer flow. To learn more, see [Get Started with the Agent API](/docs/ai/agentforce/guide/agent-api-get-started.html). * HTTP scheme: bearer ## Operations ### POST Start a session `POST /agents/{id}/sessions` Operation ID: `startSession`. Begin an agent session. The endpoint contains the ID of the Salesforce agent. You can find this ID in the URL of the agent details page. When you select the agent from Setup, use the ID at the end of the URL. #### Parameters * `id` (path, string, required) The ID of the Salesforce agent. You can find this ID in the URL of the agent details page. When you select the agent from Setup, use the ID at the end of the URL. * `Authorization` (header, string, required) Authorization information that contains the JWT. Example: `Bearer •••••`. #### Request body (required) Request payload to initiate a session. Media type: `application/json`. Schema: `StartSessionRequest`. #### Responses * **200** Response to a new session. Headers: * `x-session-mode` (string) Agent session mode. Example: `default` Media type: `application/json`. Schema: `StartSessionSyncResponseMessage`. * **400** Bad Request Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example_ ``` { "status": 400, "path": "/v6/00DRM00000067To/sessions/HelloWorldBot/messages", "requestId": "19c056ab-d909-49df-b976-65e56b6ab214", "error": "BadRequestError", "message": "Bad Request", "timestamp": 1531245973799 } ``` * **401** Access bearer token is missing or invalid Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example_ ``` { "status": 401, "path": "/v1/00DRM00000067To/chatbots/HelloWorldBot/messages", "requestId": "19c056ab-d909-49df-b976-65e56b6ab214", "error": "UnauthorizedError", "message": "Access bearer token is missing or invalid", "timestamp": 1531245973799 } ``` * **403** User forbidden from accessing the resource Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example_ ``` { "status": 403, "path": "/v1/00DRM00000067To/chatbots/HelloWorldBot/messages", "requestId": "19c056ab-d909-49df-b976-65e56b6ab214", "error": "ForbiddenError", "message": "User forbidden from accessing the resource", "timestamp": 1531245973799 } ``` * **404** Resource not found Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example_ ``` { "status": 404, "path": "/v1/00DRM00000067To/chatbots/HelloWorldBot/messages", "requestId": "19c056ab-d909-49df-b976-65e56b6ab214", "error": "NotFoundError", "message": "Resource not found", "timestamp": 1531245973799 } ``` * **422** Any exception that occurred during the request execution Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example_ ``` { "status": 422, "path": "v4.0.0/messages", "requestId": "19c056ab-d909-49df-b976-65e56b6ab214", "error": "RequestProcessingException", "message": "Cannot determine the active version for the agent", "timestamp": 1531245973799 } ``` * **423** Server is busy and cannot process the request at this time Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example_ ``` { "status": 423, "path": "/v1/00DRM00000067To/chatbots/HelloWorldBot/messages", "requestId": "19c056ab-d909-49df-b976-65e56b6ab214", "error": "ServerBusyError", "message": "Server is busy and cannot process the request at this time", "timestamp": 1531245973799 } ``` * **429** Too many requests for the server to handle Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example_ ``` { "status": 429, "path": "/v1/00DRM00000067To/chatbots/HelloWorldBot/messages", "requestId": "19c056ab-d909-49df-b976-65e56b6ab214", "error": "TooManyRequestsError", "message": "Too many requests for the server to handle", "timestamp": 1531245973799 } ``` * **503** Service is unavailable possibly because Apex or Flow calls timed out Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example_ ``` { "status": 503, "path": "/v1/00DRM00000067To/chatbots/HelloWorldBot/messages", "requestId": "19c056ab-d909-49df-b976-65e56b6ab214", "error": "ServiceUnavailable", "message": "Service is unavailable possibly because Apex/Flow calls timed out", "timestamp": 1531245973799 } ``` * **default** Something went wrong Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. ### POST Send a message (synchronous) `POST /sessions/{session-id}/messages` Operation ID: `sendMessage`. Send a synchronous message to the agent on an active session. The endpoint contains the ID of the active session, which was returned in the response of the Start Session call. #### Parameters * `session-id` (path, string, required) The ID of the active session, which is the `sessionId` value returned from the Start Session call. * `Authorization` (header, string, required) Authorization information that contains the JWT. Example: `Bearer •••••`. #### Request body (required) Request payload to continue the chat. Media type: `application/json`. Schema: `SendMessageRequest`. #### Responses * **200** Batched Response (Headless) Media type: `application/json`. Schema: `SendMessagesSyncResponseMessage`. * **400** Bad Request Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 400 response._ * **401** Access bearer token is missing or invalid Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 401 response._ * **403** User forbidden from accessing the resource Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 403 response._ * **404** Resource not found Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 404 response._ * **422** Any exception that occurred during the request execution Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 422 response._ * **423** Server is busy and cannot process the request at this time Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 423 response._ * **429** Too many requests for the server to handle Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 429 response._ * **503** Service is unavailable possibly because Apex or Flow calls timed out Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 503 response._ * **default** Something went wrong Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. ### POST Send a message (streaming) `POST /sessions/{session-id}/messages/stream` Operation ID: `sendMessageStream`. Send a streaming message to the agent on an active session. Returns an SSE stream in the response. The endpoint contains the ID of the active session, which was returned in the response of the Start Session call. #### Parameters * `session-id` (path, string, required) The ID of the active session, which is the `sessionId` value returned from the Start Session call. * `Authorization` (header, string, required) Authorization information that contains the JWT. Example: `Bearer •••••`. * `Accept` (header, string, required) Indicates which content type the sender is able to understand. For this endpoint, specify `text/event-stream`. Example: `text/event-stream`. #### Request body (required) Request payload to continue the chat. Media type: `application/json`. Schema: `SendMessageRequest`. #### Responses * **200** OK Media type: `text/event-stream`. Schema: `ServerSentEvent`. * **400** Bad Request Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 400 response._ * **401** Access bearer token is missing or invalid Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 401 response._ * **403** User forbidden from accessing the resource Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 403 response._ * **404** Resource not found Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 404 response._ * **422** Any exception that occurred during the request execution Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 422 response._ * **423** Server is busy and cannot process the request at this time Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 423 response._ * **429** Too many requests for the server to handle Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 429 response._ * **503** Service is unavailable possibly because Apex or Flow calls timed out Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 503 response._ * **default** Something went wrong Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. ### DELETE End an active session `DELETE /sessions/{session-id}` Operation ID: `endSession`. Send a message to the agent to end a session. The endpoint contains the ID of the active session, which was returned in the response of the Start Session call. #### Parameters * `session-id` (path, string, required) The ID of the active session, which is the `sessionId` value returned from the Start Session call. * `Authorization` (header, string, required) Authorization information that contains the JWT. Example: `Bearer •••••`. * `x-session-end-reason` (header, EndSessionReason, required) The reason the session ended. _Example_ ``` UserRequest ``` #### Responses * **200** Batched Response (Headless) Media type: `application/json`. Schema: `SendMessagesSyncResponseMessage`. * **400** Bad Request Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 400 response._ * **401** Access bearer token is missing or invalid Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 401 response._ * **403** User forbidden from accessing the resource Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 403 response._ * **404** Resource not found Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 404 response._ * **422** Any exception that occurred during the request execution Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 422 response._ * **423** Server is busy and cannot process the request at this time Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 423 response._ * **429** Too many requests for the server to handle Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 429 response._ * **503** Service is unavailable possibly because Apex or Flow calls timed out Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 503 response._ * **default** Something went wrong Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. ### POST Submit feedback `POST /sessions/{session-id}/feedback` Operation ID: `submitFeedback`. Submit feedback for a message. Feedback data is stored in Data 360. #### Parameters * `session-id` (path, string, required) The ID of the session, which is the `sessionId` value returned from the Start Session call. * `Authorization` (header, string, required) Authorization information that contains the JWT. Example: `Bearer •••••`. #### Request body (required) The feedback payload. Media type: `application/json`. Schema: `FeedbackMessage`. #### Responses * **202** Feedback successfully accepted. * **400** Bad Request Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 400 response._ * **401** Access bearer token is missing or invalid Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 401 response._ * **403** User forbidden from accessing the resource Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 403 response._ * **404** Resource not found Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 404 response._ * **422** Any exception that occurred during the request execution Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 422 response._ * **423** Server is busy and cannot process the request at this time Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 423 response._ * **429** Too many requests for the server to handle Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 429 response._ * **503** Service is unavailable possibly because Apex or Flow calls timed out Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. _Example: same as POST /agents/{id}/sessions 503 response._ * **default** Something went wrong Headers: * `X-Request-ID` (string) Request ID. A UUID in string format to help with request tracking. Example: `36a73651-a46d-4d16-9a8a-fd436ed62e1a` Media type: `application/json`. Schema: `Error`. ## Schemas ### StartSessionRequest * `externalSessionKey` (_ExternalSessionKey_, required) * `instanceConfig` (_InstanceConfig_, required) * `tz` (_string_) Client timezone where the customer starts the chat. Uses the tz database timezone format. Can be null. Example: `America/Los_Angeles`. * `variables` (_Variables_) * `featureSupport` (_SessionFeature_) * `streamingCapabilities` (_StreamingCapability_) * `bypassUser` (_boolean_) Indicates whether to use the agent-assigned user instead of the logged in user. If set to `true`, the API uses the user associated with the agent. If set to `false`, the API uses the user associated with the token. Set this value to `true` when using the client credentials flow. Defaults to `false`. Example: `true`. ### StartSessionSyncResponseMessage * `sessionId` (_ResponseSessionId_, required) * `_links` (_SyncLinks_, required) * `messages` (_array of AbstractResponseMessage_, required) Array of initial messages. Each message can be one of the following response message types: [Inform](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AInformMessage), [TextChunk](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ATextChunkMessage), [ValidationFailureChunk](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AValidationFailureChunkMessage), [ProgressIndicator](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AProgressIndicatorMessage), [Inquire](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AInquireMessage), [Confirm](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AConfirmMessage), [Failure](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AFailureMessage), [Escalate](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AEscalateMessage), [SessionEnded](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ASessionEndedMessage), [EndOfTurn](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AEndOfTurnMessage), [Error](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AErrorMessage). Minimum: 0. ### Error * `status` (_integer (int32)_, required) HTTP status. * `path` (_string_, required) Request path. * `requestId` (_string_, required) Request ID. A UUID in string format to help with request tracking. * `error` (_string_, required) Error class name. * `message` (_string_, required) Exception message. * `timestamp` (_number_, required) Unix timestamp. _Example_ ``` { "status": 500, "path": "/agents/00DRM00000067To/messages", "requestId": "19c056ab-d909-49df-b976-65e56b6ab214", "error": "InactiveConfigException", "message": "Config is not active", "timestamp": 1531245973799 } ``` ### SendMessageRequest Represents a send message request. * `message` (_AbstractRequestMessage_, required) * `variables` (_Variables_) ### SendMessagesSyncResponseMessage * `messages` (_array of AbstractResponseMessage_, required) Array of response messages. Each message can be one of the following response message types: [Inform](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AInformMessage), [TextChunk](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ATextChunkMessage), [ValidationFailureChunk](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AValidationFailureChunkMessage), [ProgressIndicator](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AProgressIndicatorMessage), [Inquire](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AInquireMessage), [Confirm](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AConfirmMessage), [Failure](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AFailureMessage), [Escalate](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AEscalateMessage), [SessionEnded](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ASessionEndedMessage), [EndOfTurn](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AEndOfTurnMessage), [Error](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AErrorMessage). Minimum: 0. * `_links` (_SyncLinks_, required) ### ServerSentEvent Server sent event (SSE) contents. * `id` (_string_) Event ID. Example: `1692632086370-0`. * `event` (_EventType_, required) * `retry` (_number_) Reserved for future use. * `data` (_CopilotEvent | ErrorEvent_, required) Data associated with this event. One of: `CopilotEvent`, `ErrorEvent`. ### EndSessionReason Type: `string`. Allowed values: `UserRequest`, `Transfer`, `Expiration`, `Error`, `Other`. Example: `Transfer`. ### FeedbackMessage * `feedbackId` (_FeedbackId_, required) * `feedback` (_FeedbackRating_, required) * `text` (_string_) Textual representation of user feedback. Example: `Email looks great.`. * `details` (_object_) Additional details to provide as key value pairs. Maximum properties: 10. _Example_ ``` { "userId": "uid" } ``` ### ExternalSessionKey UUID that you provide for the conversation. You can use this parameter to trace the conversation in your agent's event logs. Type: `string`. Example: `57904eb6-5352-4c5e-adf6-5f100572cf5d`. ### InstanceConfig API configuration parameters. * `endpoint` (_string_, required) My Domain URL for your Salesforce org. From Setup, search for My Domain. Copy the value shown in the Current My Domain URL field. See [Get Started with Agent API](/docs/ai/agentforce/guide/agent-api-get-started.html). Example: `https://d5e000009s7bceah-dev-ed.my.salesforce.com/`. ### Variables Array of custom and context agent variables passed to the agent during a session. See [Agent Variables](https://help.salesforce.com/s/articleView?id=ai.agent_variables.htm). Many variables are read-only and can only be set during the start session call. By default, context variables (which have the `$Context` prefix) aren't editable after the session has started, except for the `$Context.EndUserLanguage` variable. You can only modify editable variables during a send message call. When specifying variables that are derived from custom fields, omit the `__c` suffix. For instance, `Conversation_Key__c` becomes `$Context.Conversation_Key`. This array can be null. Array of `Variable`. ### SessionFeature Defines how the session supports message processing. Type: `string`. Allowed values: `Sync`, `Streaming`. Example: `Sync`. ### StreamingCapability Describes the streaming capabilities. * `chunkTypes` (_array of ChunkType_) Array of chunk types. Minimum: 0. ### ResponseSessionId Agent session ID. Use this value for the session ID when sending messages or ending a session. Type: `string`. Example: `57904eb6-5352-4c5e-adf6-5f100572cf5d`. ### SyncLinks List of Agentforce endpoints for HATEOS compliance. * `self` (_HyperLink_, required) * `messages` (_HyperLink_) * `session` (_HyperLink_) * `end` (_HyperLink_) ### AbstractResponseMessage Response message. Message can be one of the following response message types: [Inform](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AInformMessage), [TextChunk](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ATextChunkMessage), [ValidationFailureChunk](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AValidationFailureChunkMessage), [ProgressIndicator](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AProgressIndicatorMessage), [Inquire](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AInquireMessage), [Confirm](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AConfirmMessage), [Failure](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AFailureMessage), [Escalate](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AEscalateMessage), [SessionEnded](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ASessionEndedMessage), [EndOfTurn](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AEndOfTurnMessage), [Error](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AErrorMessage). * `id` (_MessageId_, required) * `type` (_string_, required) Indicates the type of message. Can be one of the following strings: [Inform](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AInformMessage), [TextChunk](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ATextChunkMessage), [ValidationFailureChunk](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AValidationFailureChunkMessage), [ProgressIndicator](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AProgressIndicatorMessage), [Inquire](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AInquireMessage), [Confirm](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AConfirmMessage), [Failure](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AFailureMessage), [Escalate](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AEscalateMessage), [SessionEnded](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ASessionEndedMessage), [EndOfTurn](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AEndOfTurnMessage), [Error](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AErrorMessage). Example: `Inform`. ### AbstractRequestMessage Represents the message to be sent. Can be one of the following request message types: [Text](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ATextMessage), [Reply](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AReplyMessage), [Cancel](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ACancelMessage), [TransferFailed](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ATransferFailedMessage), [TransferSucceeded](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ATransferSucceededMessage), [PlanTemplate](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3APlanTemplateMessage). * `type` (_string_, required) Request message type. Can be one of the following types: [Text](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ATextMessage), [Reply](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AReplyMessage), [Cancel](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ACancelMessage), [TransferFailed](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ATransferFailedMessage), [TransferSucceeded](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ATransferSucceededMessage), [PlanTemplate](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3APlanTemplateMessage). Allowed values: `Text`, `Reply`, `Cancel`, `TransferFailed`, `TransferSucceeded`, `PlanTemplate`. * `sequenceId` (_SequenceId_, required) _Example_ ``` { "type": "Text", "sequenceId": 1, "text": "Can you provide a summary of my orders?" } ``` ### EventType Type of streaming event. See [Inform](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AInformMessage), [TextChunk](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ATextChunkMessage), [ValidationFailureChunk](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AValidationFailureChunkMessage), [ProgressIndicator](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AProgressIndicatorMessage), [Inquire](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AInquireMessage), [Confirm](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AConfirmMessage), [Failure](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AFailureMessage), [Escalate](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AEscalateMessage), [SessionEnded](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ASessionEndedMessage), [EndOfTurn](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AEndOfTurnMessage), [Error](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AErrorMessage). Type: `string`. Allowed values: `UNKNOWN`, `END_OF_TURN`, `PROGRESS_INDICATOR`, `INFORM`, `INQUIRE`, `CONFIRM`, `FAILURE`, `SESSION_ENDED`, `ERROR`, `ESCALATE`, `TEXT_CHUNK`. ### CopilotEvent Event wrapper. * `timestamp` (_number_) Event timestamp. Example: `1716299066`. * `originEventId` (_EventId_) * `traceId` (_string_) Event trace ID. Example: `69feac6d79e075633486f4f722fd97c3`. * `offset` (_number_) Event offset. * `message` (_AbstractResponseMessage_) Response message. Message can be one of the following response message types: [Inform](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AInformMessage), [TextChunk](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ATextChunkMessage), [ValidationFailureChunk](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AValidationFailureChunkMessage), [ProgressIndicator](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AProgressIndicatorMessage), [Inquire](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AInquireMessage), [Confirm](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AConfirmMessage), [Failure](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AFailureMessage), [Escalate](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AEscalateMessage), [SessionEnded](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3ASessionEndedMessage), [EndOfTurn](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AEndOfTurnMessage), [Error](https://developer.salesforce.com/docs/ai/agentforce/references/agent-api?meta=type%3AErrorMessage). ### ErrorEvent ### FeedbackId Unique ID to identify the generation. Used to submit feedback. Type: `string`. Example: `9247bbd8-5ed9-11ee-8c99-0242ac120002`. ### FeedbackRating Feedback rating, suggesting a thumbs up or thumbs down. Type: `string`. Allowed values: `GOOD`, `BAD`. ### Variable Custom or context variable passed to the agent during a session. See [Agent Variables](https://help.salesforce.com/s/articleView?id=ai.agent_variables.htm). Many variables are read-only and can only be set during the start session call. By default, context variables (which have the `$Context` prefix) aren't editable after the session has started, except for the `$Context.EndUserLanguage` variable. You can only modify editable variables during a send message call. When specifying variables that are derived from custom fields, omit the `__c` suffix. For instance, `Conversation_Key__c` becomes `$Context.Conversation_Key`. * `name` (_string_, required) API name for the agent variable. Example: `$Context.EndUserLanguage`. * `type` (_string_, required) Variable type. Allowed values: `Object`, `Json`, `Boolean`, `Date`, `DateTime`, `Money`, `Number`, `Text`, `Ref`, `List`. Example: `Text`. * `value` (_string_, required) Variable value. Example: `en_US`. ### ChunkType Defines the types of stream chunks you'd like to receive when streaming. Type: `string`. Allowed values: `Text`. ### HyperLink Hyperlink object included in the links schema. * `href` (_string_) Link to the endpoint. Example: `https://api.salesforce.com/sessions`. ### MessageId UUID that references this message. Type: `string`. Example: `a133c185-73a7-4adf-b6d9-b7fd62babb4e`. ### SequenceId Client-generated sequence number of the message in a session. Increase this number for each subsequent message. Type: `number`. Example: `1`. ### EventId Unique ID to identify the event. Type: `string`. Example: `auMZc8ZRv37sIW2iJKq3M9MFx1YvV11A2x`. ### CancelMessage Represents a cancel message request. Includes all fields of `AbstractRequestMessage`. * `inReplyToMessageId` (_InReplyToMessageId_) ### ReplyMessage Used when answering a question with a choice of multiple records. Includes all fields of `AbstractRequestMessage`. * `inReplyToMessageId` (_InReplyToMessageId_) * `reply` (_array of TargetTypeMessage_, required) Minimum items: 1. ### EndOfTurnMessage Represents the end of the turn. Includes all fields of `AbstractResponseMessage`. ### ProgressIndicatorMessage Represents a progress indicator. Includes all fields of `AbstractResponseMessage`. * `indicatorType` (_ProgressIndicatorType_, required) * `message` (_string_, required) Status message sent to the user. Example: `Looking up your order`. ### ProgressIndicatorType Indicates the type of progress indicator. Type: `string`. Allowed values: `ACTION`. Example: `ACTION`. ### PlanTemplateMessage Represents a plan template message. Represents the type of message to be sent by client when it wants to execute an existing plan. Includes all fields of `AbstractRequestMessage`. * `inReplyToMessageId` (_InReplyToMessageId_) * `details` (_object_, required) Represents details of plan to be executed. Plan templates are metadata and available to planner service. * `planId` (_string_) ID of the plan template. * `intent` (_string_) A string representing the user intent behind this plan. * `userUtterance` (_string_) User utterance that should be used in conversation history as a result of executing this plan. * `variables` (_object_) Contains name value pairs capturing the variable substitutions in the plan. ### TextChunkMessage Represents a chunk of the text response. Includes all fields of `AbstractResponseMessage`. * `offset` (_number_, required) Offset value. * `message` (_string_, required) Text chunk message. * `formatType` (_TextFormatType_, required) ### TextFormatType The text format type. Type: `string`. Allowed values: `Unknown`, `Text`. ### ValidationFailureChunkMessage Indicates that there was a failure validating the agent's response. If you receive a validation failure chunk, remove all previously rendered chunks and display only the new streamed content. Includes all fields of `AbstractResponseMessage`. * `offset` (_number_, required) Token offset value. * `reason` (_string_) Reason for validation failure. Example: `UNGROUNDED`. ### InformMessage Informs caller of response. Includes all fields of `AbstractResponseMessage`. * `feedbackId` (_FeedbackId_, required) * `planId` (_PlanId_) * `isContentSafe` (_ContentSafety_, required) * `message` (_string_, required) Example: `Great, the annual revenue for the specified account has been updated to $1,000,000`. * `result` (_array of SourceTypeMessage_) Array of results. Minimum items: 1. * `citedReferences` (_array of CitedReference_) Array of citations. Minimum items: 0. ### InquireMessage Indicates that more information is required. Includes all fields of `AbstractResponseMessage`. * `feedbackId` (_FeedbackId_, required) * `planId` (_PlanId_) * `isContentSafe` (_ContentSafety_) * `message` (_string_) The message string. * `collect` (_array of InquireCollectMessage_, required) List of data to be collected. Minimum items: 0. ### InquireCollectMessage Inquire type * `targetType` (_TargetTypeId_, required) * `targetProperty` (_TargetPropertyId_) * `data` (_SourceTypeMessage_) ### ConfirmMessage Indicates that the agent is asking the user to verify that an action should be taken. Includes all fields of `AbstractResponseMessage`. * `feedbackId` (_FeedbackId_, required) * `planId` (_PlanId_) * `isContentSafe` (_ContentSafety_) * `message` (_string_) * `confirm` (_array of TargetTypeMessage_, required) List of data to be collected. Minimum items: 1. ### ErrorMessage Indicates there was an error in the response. Includes all fields of `AbstractResponseMessage`. * `feedbackId` (_FeedbackId_, required) * `httpStatus` (_integer (int32)_, required) Error HTTP status code. Example: `500`. * `traceId` (_string_) Error trace ID. Example: `69feac6d79e075633486f4f722fd97c3`. * `error` (_string_, required) Error class name. Example: `NullPointerException`. * `message` (_string_, required) Error message. Example: `Something went wrong.`. * `timestamp` (_number_) Error UNIX timestamp. Example: `1531245973799`. * `expected` (_boolean_, required) Indicates whether the error was expected. Example: `true`. ### RichContentCapability * `messageTypes` (_array of MessageTypeCapability_, required) Minimum: 1. ### MessageTypeCapability * `messageType` (_MessageType_, required) * `formatTypes` (_array of FormatTypeCapability_, required) Minimum: 1. ### FormatTypeCapability * `formatType` (_FormatType_, required) ### MessageType Message type that supports rich content output formats. * `ChoicesMessage`: Represents multiple choice content. Type: `string`. Allowed values: `ChoicesMessage`. Example: `ChoicesMessage`. ### FormatType The rendering format of a message. Describes how the message looks. Type: `string`. Allowed values: `MessageDefinition`, `Text`. Example: `MessageDefinition`. ### PlanId Unique ID to identify the plan. Type: `string`. Example: `9247bbd8-5ed9-11ee-8c99-0242ac120002`. ### ContentSafety Indicates whether the content is deemed as safe. A false value doesn't necessarily mean that the content isn't toxic. Type: `boolean`. Example: `true`. ### CitedReference * `type` (_string_, required) Type of citation. This value can be either a CRM record (`record`) or an external link (`link`). Allowed values: `record`, `link`. * `value` (_string_, required) External link address. * `recordId` (_string_) Salesforce org record ID. * `label` (_string_) UI label for citation. * `inlineMetadata` (_array of InlineReferenceMetadata_) Inline metadata information used for inline citations. ### InlineReferenceMetadata * `claim` (_string_, required) Text from the agent response relevant to this reference. * `location` (_integer_, required) Index location for where this citation should be placed. ### SourceTypeMessage Bundle for a source type. * `type` (_SourceTypeId_, required) * `property` (_SourcePropertyId_) * `value` (_TypeValue_, required) ### SourceTypeId The action type ID. See [Agent Actions](https://help.salesforce.com/s/articleView?id=ai.copilot_actions.htm). Type: `string`. Example: `copilotActionOutput/EmployeeCopilot__UpdateRecordFields`. ### SourcePropertyId The action property ID. See [Agent Actions](https://help.salesforce.com/s/articleView?id=ai.copilot_actions.htm). Type: `string`. Example: `result`. ### TargetTypeId The action type ID. See [Agent Actions](https://help.salesforce.com/s/articleView?id=ai.copilot_actions.htm). Type: `string`. Example: `@aiFunctionInput/BookFlight`. ### TargetTypeMessage Bundle for a target type. * `type` (_TargetTypeId_, required) * `property` (_TargetPropertyId_) * `value` (_TypeValue_, required) ### TargetPropertyId The action property ID. See [Agent Actions](https://help.salesforce.com/s/articleView?id=ai.copilot_actions.htm). Type: `string`. Example: `flightInfo`. ### TypeValue A type value. Type: `any`. Example: `a free form string or an object or an array`. ### InReplyToMessageId Message ID of the previous response you are replying to. Type: `string`. Example: `a133c185-73a7-4adf-b6d9-b7fd62babb4e`. ### BooleanVariable Includes all fields of `Variable`. * `value` (_boolean_, required, nullable) Boolean value. Example: `true`. ### DateVariable Includes all fields of `Variable`. * `value` (_string_, required, nullable) Date in the ISO\_LOCAL\_DATE format, 'YYYY-MM-DD'. Example: `2021-09-21`. ### DateTimeVariable Includes all fields of `Variable`. * `value` (_string_, required, nullable) Datetime in the ISO\_LOCAL\_DATE\_TIME format, 'YYYY-MM-DDTHH:MM:SS'. Example: `2018-09-21T14:30:00`. ### MoneyVariable Includes all fields of `Variable`. * `value` (_string_, required, nullable) Money in the format, '3\_LETTER\_CURRENCY\_CODE AMOUNT'. Example: `USD 10.40`. ### NumberVariable Includes all fields of `Variable`. * `value` (_number_, required, nullable) Variable value in number format. Example: `10`. ### TextVariable Includes all fields of `Variable`. * `value` (_string_, required, nullable) Variable value in text format. Example: `Thanks for your order!`. ### ObjectVariable Includes all fields of `Variable`. * `value` (_array of Variable_, required) Variable value as an object. _Example_ ``` [ { "name": "fullName", "type": "text", "value": "Matt Smith" } ] ``` ### RefVariable Includes all fields of `Variable`. * `value` (_string_, required, nullable) Variable value in reference ID format. Example: `1M5xx000000000BCAQ`. ### ListVariable Includes all fields of `Variable`. * `value` (_array of object_, required, nullable) Array of objects. _Example_ ``` [ { "type": "ref", "value": "1M5xx000000000BCAQ" } ] ``` ### JsonVariable Includes all fields of `Variable`. * `value` (_object_, required) Variable value in JSON format. ### Referrer * `type` (_string_, required) Referrer type. Allowed values: `Salesforce:Core:Bot:Id`, `Salesforce:BotRuntime:Session:Id`. Example: `Salesforce:Core:Bot:Id`. * `value` (_string_, required) ID of referrer. Example: `string`. ### TransferFailedMessage Represents a transfer failed message. Includes all fields of `AbstractRequestMessage`. * `inReplyToMessageId` (_InReplyToMessageId_) * `reason` (_string_, required) Reason for the failed transfer. Allowed values: `NoAgentAvailable`, `Error`. Example: `NoAgentAvailable`. * `description` (_string_, nullable) Description of why the transfer failed. ### TransferSucceededMessage Represents a transfer succeeded message. Includes all fields of `AbstractRequestMessage`. * `inReplyToMessageId` (_InReplyToMessageId_) ### TextMessage Represents a text request. Includes all fields of `AbstractRequestMessage`. * `inReplyToMessageId` (_InReplyToMessageId_) * `text` (_string_, required) Text reply to the agent. ### SessionEndedMessage Indicates the session has ended. Includes all fields of `AbstractResponseMessage`. * `reason` (_string_, required) Reason the session ended. Allowed values: `ClientRequest`, `TransferFailedNotConfigured`, `Action`, `Error`, `InfiniteLoopDetected`. Example: `ClientRequest`. * `feedbackId` (_FeedbackId_) ### FailureMessage Indicates that something didn't execute properly. Includes all fields of `AbstractResponseMessage`. * `feedbackId` (_FeedbackId_, required) * `message` (_string_) * `planId` (_PlanId_) * `isContentSafe` (_ContentSafety_) * `code` (_string_, required) Allowed values: `ACTION_FAILED`, `ESCALATE`. * `errors` (_array of string_) Failure information. ### EscalateMessage Indicates that a human rep should handle this request. The escalation message is automatically translated based on the end user's language setting. If the language isn't supported, the original message is returned without translation. Includes all fields of `AbstractResponseMessage`. * `feedbackId` (_FeedbackId_, required) * `targets` (_array of object_, required) Array of transfer targets. Minimum: 0. * `type` (_string_, required) Type of the transfer target. Allowed values: `Salesforce:Core:Bot:Id`, `Salesforce:Core:Queue:Id`, `Salesforce:Core:Skill:Id`, `Salesforce:Core:Flow:Id`. Example: `Salesforce:Core:Bot:Id`. * `value` (_string_, required) ID of the transfer target. ### Status * `status` (_string_, required) Health status of Agent API. Allowed values: `UP`, `DOWN`. Example: `UP`. # Agent API Considerations Review these considerations before you use the Agent API. ## Supported Agent Types The Agent API isn’t supported for agents of type “Agentforce (Default)”. ## Usage and Billing Agent API usage impacts credit consumption as described in the following Salesforce help topic: [Generative AI Usage and Billing](https://help.salesforce.com/s/articleView?id=ai.generative_ai_usage.htm). ## API Timeout The Agent API has a 120-second timeout. When a call times out, you receive an HTTP 500 response. ## Government Cloud If your org is on Government Cloud, use `api.gov.salesforce.com` as the base endpoint for all Agent API requests instead of `api.salesforce.com`. The path and request format are otherwise identical to the standard endpoint. For example, to start a session, use `https://api.gov.salesforce.com/einstein/ai-agent/v1/agents/{AGENT_ID}/sessions`. ## See Also - [Get Started with Agent API](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.md) - [Agent API Examples](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-examples.md) - [Agent API Troubleshooting](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-troubleshooting.md) - [Agent API Reference](/docs/ai/agentforce/references/agent-api?meta=summary) # Agent API Developer Guide Bring the power of generative AI to your business with Agentforce. Build intelligent, trusted, and customizable AI agents and empower your users to get more done with Salesforce. With Agent API, you have access to your goal-oriented, autonomous AI agents from anywhere that can call a REST API. - Connect to an Agentforce agent from your website. - Create and deploy headless agents to automate functionality without UI constraints. - Connect agents to your favorite platforms and workflows using standardized API endpoints. - Build an agentic ecosystem by invoking Agentforce agents from other agents. ## Agent API Resources - [Get Started with Agent API](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.md) - [Agent API Session Lifecycle](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-lifecycle.md) - [Agent API Examples](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-examples.md) - [Agent API Considerations](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-considerations.md) - [Agent API Troubleshooting](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-troubleshooting.md) - [Agent API Reference](/docs/ai/agentforce/references/agent-api?meta=summary) - [Agent API Postman Collection](https://www.postman.com/salesforce-developers/salesforce-developers/collection/gwv9bjy/agent-api) ## See Also - _Salesforce Help_: [Calling an Agent from a Flow or Apex Class](https://help.salesforce.com/s/articleView?id=ai.agent_custom_invocable_action_flow_apex.htm) # Agent API Examples This section provides examples using the Agent API endpoints. To onboard, see [Get Started with Agent API](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.md). **note:** The examples on this page use `api.salesforce.com` as the base endpoint. If your org is on Government Cloud, replace `api.salesforce.com` with `api.gov.salesforce.com` in every Agent API request. ## Postman Collection The quickest way to get started with the Agent API is with our [Postman collection](https://www.postman.com/salesforce-developers/salesforce-developers/collection/gwv9bjy/agent-api). ## Start Session This curl command creates a new agent session with the Agent API. ```bash curl --location -X POST https://api.salesforce.com/einstein/ai-agent/v1/agents/{AGENT_ID}/sessions \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer {ACCESS_TOKEN}' \ --data '{ "externalSessionKey": "{RANDOM_UUID}", "instanceConfig": { "endpoint": "https://{MY_DOMAIN_URL}" }, "streamingCapabilities": { "chunkTypes": ["Text"] }, "bypassUser": true }' ``` **note:** The `bypassUser` parameter indicates whether to use the agent-assigned user instead of the logged in user. If set to `true`, the API uses the user associated with the agent. If set to `false`, the API uses the user associated with the token. To make this request, these values are required. - `AGENT_ID`: The ID of the agent that you want to interact with. The method for obtaining this ID depends on which builder you used to create your agent. See [Get the Agent ID for an Agent](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-agent-id.md) for detailed instructions. - `RANDOM_UUID`: A random UUID value that you provide to represent the session key. You can use this parameter to trace the conversation in your agent's event logs. - `ACCESS_TOKEN`: The token that you created in [Create a Token](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.md#create-a-token). - `MY_DOMAIN_URL`: From Setup, search for **My Domain**. Copy the value shown in the **Current My Domain URL** field. - Specify `application/json` in the `Content-Type` header to indicate JSON content in the request. This example shows a start session response. The response returns the session ID (`sessionId`) value, which is required when sending messages to an agent. ```json { "sessionId": "8e715939-a121-40ec-80e3-a8d1ac89da33", "_links": { "self": null, "messages": { "href": "https://api.salesforce.com/einstein/ai-agent/v1/sessions/8e715939-a121-40ec-80e3-a8d1ac89da33/messages/stream" }, "session": { "href": "https://api.salesforce.com/einstein/ai-agent/v1/agents/0XxQZ0000000Ty50AE/sessions" }, "end": { "href": "https://api.salesforce.com/einstein/ai-agent/v1/sessions/8e715939-a121-40ec-80e3-a8d1ac89da33" } }, "messages": [ { "type": "Inform", "id": "8e7cafae-0eb5-44b1-9195-21f1cd6e1f4b", "feedbackId": "", "planId": "", "isContentSafe": true, "message": "Hi, I'm an AI service assistant. How can I help you?", "result": [], "citedReferences": [] } ] } ``` For API reference info, see [Start Session](/docs/ai/agentforce/references/agent-api?meta=startSession). ## Send Synchronous Messages When you send a message by using the synchronous endpoint, the server sends back the response synchronously in one response. To use the streaming endpoint, see [Send Streaming Messages](#send-streaming-messages). Before sending messages, you must start a session. See [Start Session](#start-session). This curl command sends a message to the synchronous endpoint. ```bash curl --location 'https://api.salesforce.com/einstein/ai-agent/v1/sessions/{SESSION_ID}/messages' \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer {ACCESS_TOKEN}' \ --data '{ "message": { "sequenceId": {SEQUENCE_ID}, "type": "Text", "text": "Show me the cases associated with Lauren Bailey." } }' ``` To make this request, these values are required. - `SESSION_ID`: The session ID found in the response payload when you created a session. - `ACCESS_TOKEN`: The token that you created in [Create a Token](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.md#create-a-token). - `SEQUENCE_ID`: A number that you provide to represent the sequence ID. Increase this number for each subsequent message in this session. - Specify `application/json` in the `Content-Type` header to indicate JSON content in the request. This example shows a potential response to a synchronous send message request. ```json { "messages": [ { "type": "Inform", "id": "ceb6b5de-6063-4e39-bc02-91e9bf7da867", "metrics": {}, "feedbackId": "0bc8720e-e010-4129-87bb-70caaa885ee4", "planId": "0bc8720e-e010-4129-87bb-70caaa885ee4", "isContentSafe": true, "message": "Here are two cases related to Lauren Bailey:\n\n1. Case Number: 00001116\n - Subject: I have a question about my bill\n - Description: When I received my most recent bill, I noticed there was a charge I didn't recognize. Can you look over my orders and help me understand what this might have been? Thank you!\n - Status: New\n - Created Date: 2025-04-05\n2. Case Number: 00001106\n - Subject: I have a product suggestion.\n - Description: I've been using your products for a long time, and I have a suggestion that I think would make them even better. What's the best way to share this with you?\n - Status: Closed\n - Created Date: 2025-04-05\n - Closed Date: 2022-10-13.", "result": [], "citedReferences": [] } ], "_links": { …(shortened) } } ``` For API reference info, see [Send Synchronous Messages](/docs/ai/agentforce/references/agent-api?meta=sendMessage). ## Send Streaming Messages When you send a message using the streaming endpoint, the server sends back information using the server-sent event (SSE) protocol. To use the synchronous endpoint, see [Send Synchronous Messages](#send-synchronous-messages). Before sending messages, you must start a session. See [Start Session](#start-session). This curl command sends a message to the streaming endpoint. ```bash curl --location 'https://api.salesforce.com/einstein/ai-agent/v1/sessions/{SESSION_ID}/messages/stream' \ --header 'Accept: text/event-stream' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer {ACCESS_TOKEN}' \ --data '{ "message": { "sequenceId": {SEQUENCE_ID}, "type": "Text", "text": "Show me the cases associated with Lauren Bailey." } }' ``` To make this request, these values are required. - `SESSION_ID`: The session ID found in the response payload when you created a session. - `ACCESS_TOKEN`: The token that you created in [Create a Token](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.md#create-a-token). - `SEQUENCE_ID`: A number that you provide to represent the sequence ID. Increase this number for each subsequent message in this session. - Specify `application/json` in the `Content-Type` header to indicate JSON content in the request. - Specify `text/event-stream` in the `Accept` header so that the response contains the message stream. When you make a streaming request, messages return in the event stream. This example shows a [`ProgressIndicator`](/docs/ai/agentforce/references/agent-api?meta=type%3AProgressIndicatorMessage) event, which indicates that a response is in progress. ```json { "timestamp": 1736902938827, "originEventId": "1736902935340-REQ", "traceId": "2fdb1d5e7eb48d35b9d1ba402eeb4b69", "offset": 0, "message": { "type": "ProgressIndicator", "id": "c4410599-8c0a-412d-910f-a60e4159d807", "indicatorType": "ACTION", "message": "Working on it" } ``` The message streams in text chunk increments. This example shows a [`TextChunk`](/docs/ai/agentforce/references/agent-api?meta=type%3ATextChunkMessage) event. ```json { "timestamp": 1736902952425, "originEventId": "1736902935340-REQ", "traceId": "2fdb1d5e7eb48d35b9d1ba402eeb4b69", "offset": 1, "message": { "type": "TextChunk", "id": "6fc64974-9c20-484e-8b8c-105e460d4a00", "offset": 1, "message": "Here", "formatType": "Text" } } ``` The API returns the complete message in an [`Inform`](/docs/ai/agentforce/references/agent-api?meta=type%3AInformMessage) event. ```json { "messages": [ { "type": "Inform", "id": "f0313bcb-65a2-4abb-9d84-b872247b1420", "metrics": {}, "feedbackId": "ab403163-b87f-4e4b-9fa6-18670a2be655", "planId": "ab403163-b87f-4e4b-9fa6-18670a2be655", "isContentSafe": true, "message": "Here are two cases related to Lauren Bailey:\n\n1. Case Number: 00001116\n - Subject: I have a question about my bill\n - Description: When I received my most recent bill, I noticed there was a charge I didn't recognize. Can you look over my orders and help me understand what this might have been? Thank you!\n - Status: New\n - Created Date: 2025-04-05\n2. Case Number: 00001106\n - Subject: I have a product suggestion.\n - Description: I've been using your products for a long time, and I have a suggestion that I think would make them even better. What's the best way to share this with you?\n - Status: Closed\n - Created Date: 2025-04-05\n - Closed Date: 2022-10-13", "result": [], "citedReferences": [] } ], "_links": { "self": null, "messages": { "href": "https://api.salesforce.com/einstein/ai-agent/v1/sessions/499713a4-b441-4234-bafd-392ee08dbd01/messages" }, "messagesStream": { "href": "https://api.salesforce.com/einstein/ai-agent/v1/sessions/499713a4-b441-4234-bafd-392ee08dbd01/messages/stream" }, "session": { "href": "https://api.salesforce.com/einstein/ai-agent/v1/agents/0XxQZ0000000Ty50AE/sessions" }, "end": { "href": "https://api.salesforce.com/einstein/ai-agent/v1/sessions/499713a4-b441-4234-bafd-392ee08dbd01" } } } ``` The API returns an [`EndOfTurn`](/docs/ai/agentforce/references/agent-api?meta=type%3AEndOfTurnMessage) event when the response is complete. ```json { "timestamp": 1736902953027, "originEventId": "1736902935340-REQ", "traceId": "2fdb1d5e7eb48d35b9d1ba402eeb4b69", "offset": 0, "message": { "type": "EndOfTurn", "id": "2a2be92b-f479-481a-9f22-1e5bf39e038e" } } ``` **tip:** If you receive a [ValidationFailureChunk](/docs/ai/agentforce/references/agent-api?meta=type%3AValidationFailureChunkMessage) streaming event, there was a failure validating the agent's response. Remove all previously rendered chunks and display only the new streamed content. For API reference info, see [Send Streaming Messages](/docs/ai/agentforce/references/agent-api?meta=sendMessageStream). ## Send Agent Variables For an example using agent variables, see [Send Agent Variables with the Agent API](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-variables.md). ## Handle Citations Some message responses include cited sources. Cited sources surface in the `citedReferences` array of an `Inform` response message. Citations can either appear as sources at the bottom of the response, or inline citations (using the `inlineMetadata` object) that are associated with a specific location in the response. ```json { "timestamp": 1745599724677, "originEventId": "1745599714159-REQ", "traceId": "310046aaded69001de5dbddaec4f8a75", "offset": 0, "message": { "type": "Inform", "id": "484c59e5-9c24-4735-ba55-0707a071a9e7", "feedbackId": "a9695531-091b-42de-8b4d-61f3aaadd42e", "planId": "a9695531-091b-42de-8b4d-61f3aaadd42e", "isContentSafe": true, "message": "The 2024 Acura ZDX is Acura's first-ever all-electric vehicle, featuring:\n\n- Maximum Range: 313 miles\n- Starting Price: $65,850\n- Interior: Premium and spacious\n- Charging: Compatible with Tesla's Supercharger network\n- Trim Levels: Two available trims\n- Platform: Shares a platform with the Cadillac Lyriq and is built in the same Tennessee factory\n- Sales: Conducted exclusively online\n- Pricing:\n - ZDX A-Spec: $65,850\n - ZDX A-Spec with all-wheel drive: $69,850\n - ZDX Type S: $74,850\n- Tax Credit: Eligible for a federal tax credit of up to $7,500\n\nIf you have any more questions or need further details, feel free to ask!", "result": [], "citedReferences": [ { "type": "link", "value": "https://myorgdomain.salesforce.com/ka0RZ000002DzSmYAK", "recordId": "ka0RZ000002DzSmYAK", "label": null, "inlineMetadata": [ { "claim": "The 2024 Acura ZDX is Acura's first-ever all-electric vehicle, featuring:\n\n- Maximum Range: 313 miles\n- Starting Price: $65,850\n- Interior: Premium and spacious\n- Charging: Compatible with Tesla's Supercharger network\n- Trim Levels:", "location": 236 } ] }, { "type": "link", "value": "https://myorgdoamin.salesforce.com/ka0RZ000002E0INYA0", "recordId": "ka0RZ000002E0INYA0", "label": null, "inlineMetadata": [ { "claim": "Two available trims\n- Platform: Shares a platform with the Cadillac Lyriq and is built in the same Tennessee factory\n- Sales: Conducted exclusively online\n- Pricing:\n - ZDX A-Spec: $65,850\n - ZDX A-Spec with all-wheel drive: $69,850\n - ZDX Type S: $74,850\n- Tax Credit: Eligible for a federal tax credit of up to $7,500", "location": 562 } ] } ] } } ``` For API reference info, see [InformMessage](/docs/ai/agentforce/references/agent-api?meta=type%3AInformMessage) and [CitedReference](/docs/ai/agentforce/references/agent-api?meta=type%3ACitedReference). ## End Session This curl command sends an end session request. ```bash curl --location --request DELETE 'https://api.salesforce.com/einstein/ai-agent/v1/sessions/{SESSION_ID}' \ --header 'x-session-end-reason: UserRequest' \ --header 'Authorization: Bearer {ACCESS_TOKEN}' ``` To make this request, these values are required. - `SESSION_ID`: The session ID found in the response payload when you created a session. - `ACCESS_TOKEN`: The token that you created in [Create a Token](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.md#create-a-token). This example shows a response to an end message request. ```json { "messages": [ { "type": "SessionEnded", "id": "c5692ca0-ee1b-414a-9d96-4e7862456500", "reason": "ClientRequest", "feedbackId": "" } ], "_links": { "self": null, "messages": { "href": "https://api.salesforce.com/einstein/ai-agent/v1/sessions/8d705938-a121-40ec-80e3-a8d1ac89da33/messages/stream" }, "session": { "href": "https://api.salesforce.com/einstein/ai-agent/v1/agents/0XxQZ0000000Ty50AE/sessions" }, "end": { "href": "https://api.salesforce.com/einstein/ai-agent/v1/sessions/8d705938-a121-40ec-80e3-a8d1ac89da33" } } } ``` For API reference info, see [End Session](/docs/ai/agentforce/references/agent-api?meta=endSession). ## Submit Feedback You can also submit feedback to the org based on the agent’s responses. This feedback is stored in Data 360. To learn more, see [About Generative AI Audit and Feedback Data](https://help.salesforce.com/s/articleView?id=ai.generative_ai_feedback_about.htm). ```bash curl -v --location 'https://api.salesforce.com/einstein/ai-agent/v1/sessions/{SESSION_ID}/feedback' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer {ACCESS_TOKEN}' \ --data '{ "feedbackId": "9247bbd8-5ed9-11ee-8c99-0242ac120002", "feedback": "GOOD", "text": "Email looks great" }' ``` To make this request, these values are required. - `SESSION_ID`: The session ID found in the response payload when you created a session. - `ACCESS_TOKEN`: The token that you created in [Create a Token](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.md#create-a-token). - Specify `application/json` in the `Content-Type` header to indicate JSON content in the request. If the feedback was received, you get an HTTP 201 response. For API reference info, see [Submit Feedback](/docs/ai/agentforce/references/agent-api?meta=submitFeedback). ## See Also - [Get Started with Agent API](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.md) - [Send Agent Variables with the Agent API](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-variables.md) - [Agent API Postman Collection](https://www.postman.com/salesforce-developers/salesforce-developers/collection/gwv9bjy/agent-api) - [Send Agent Variables with the Agent API](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-variables.md) - [Agent API Session Lifecycle](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-lifecycle.md) - [Agent API Considerations](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-considerations.md) - [Agent API Troubleshooting](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-troubleshooting.md) - [Agent API Reference](/docs/ai/agentforce/references/agent-api?meta=summary) - _Developer Relations YouTube Video_: [Integrate Agentforce with Microsoft Teams](https://www.youtube.com/watch?v=cbIOq_rQang) # Agent API Session Lifecycle To communicate with an agent through the Agent API, you must [create a session](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-examples.md#start-session). Then you [send messages](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-examples.md#send-synchronous-messages) to the agent by using the ID associated with that session. The agent keep tracks of the context throughout the session. When you’re finished working with the agent, [end the session](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-examples.md#end-session). ![API Flow](https://developer.salesforce.com/media/agent-api-lifecycle.svg '{"class": "image-full"}') The Agent API provides endpoints for each stage in this lifecycle, along with an endpoint to submit feedback on a response. ## Synchronous and Streaming Messages Sending and receiving messages can be performed synchronously or with the streaming endpoint. The [synchronous endpoint](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-examples.md#send-synchronous-messages) is best for simple use cases where you want the entire response in one shot. The [streaming endpoint](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-examples.md#send-streaming-messages) is best if you intend to show the response to the user as the chunks of content arrive, like in a real-time chat conversation. ## See Also - [Get Started with Agent API](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.md) - [Agent API Examples](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-examples.md) - [Agent API Postman Collection](https://www.postman.com/salesforce-developers/salesforce-developers/collection/gwv9bjy/agent-api) - [Agent API Reference](/docs/ai/agentforce/references/agent-api?meta=summary) # Agent API Troubleshooting Review these troubleshooting tips if you run into issues when calling the API. ## HTTP 400 Response: Bad Request If you receive an HTTP 400 response, there's a problem with your request. - **Message field in response contains "{VALUE} is not a valid agent ID"**. Verify that your agent ID is correct in your API request. See [Call the API](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.md#call-the-api). ## HTTP 401 Response: Unauthorized If you recieve an HTTP 401 response, there's typically an authorization issue. Review [Get Started with Agent API](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.md). ## HTTP 404 Response: Not Found If you receive an HTTP 404 response, verify that you're using the correct token and that you're using the correct endpoint. Review [Get Started with Agent API](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.md). If your org is on Government Cloud, make sure you're calling `api.gov.salesforce.com` instead of `api.salesforce.com`. ## HTTP 423 Response: Session Already Locked Exception If you receive an HTTP 423 response, verify that you don't have any requests in progress as the API only supports one request at a time. Review [Get Started with Agent API](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.md). ## HTTP 500 Response: Internal Server Error If you receive an HTTP 500 response, verify that you've followed the setup instructions correctly. - **Message field in response contains "Unsupported Media Type"**. Use the correct `Content-Type` value in the header: `Content-Type: application/json`. - **Error field in response contains "EngineConfigLookupException"**. When specifying your domain in the [start session endpoint](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-examples.md#start-session), make sure that you're using the My Domain endpoint for your org. From Setup, search for **My Domain**. Copy the value shown in the **Current My Domain URL** field. - **Error field in response contains "HttpServerErrorException"**. Verify that you are using the correct agent ID in the endpoint. See [Get the Agent ID for an Agent](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-agent-id.md) for instructions on obtaining your agent ID. - For other issues, review [Get Started with Agent API](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.md). ## See Also - [Get Started with Agent API](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.md) - [Agent API Examples](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-examples.md) - [Agent API Considerations](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-considerations.md) - [Agent API Reference](/docs/ai/agentforce/references/agent-api?meta=summary) # Agent Script Write scripts for your agents to control the conversation flow and perform complex operations. - [Agent Script Reference](/docs/ai/agentforce/guide/ascript-reference.html) # Agent Script Blocks A script consists of blocks where each block contains a set of properties. These properties can describe data or procedures. Agent Script contains several different block types. ![Agent Script Blocks](https://developer.salesforce.com/media/agent-script/agent-script-blocks4.svg '{"class": "image-sm"}') This section gives you a high-level understanding of each block type. ## System Block The system block contains general instructions for the agent. This information includes a list of message prompts that the agent uses during specific scenarios. `welcome` and `error` are required messages: - For multiline messages, use the pipe symbol ("|") - To personalize messages or include other context information, use [linked variables](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-variables.md#linked-variables). For example, to dynamically inject the user's preferred name into the welcome message, use `{!@variables.userPreferredName}`. In this example, if the `userPreferredName` is `Sam`, customers see the welcome message "Hi Sam! I'm your personal shopping assistant". ```agentscript system: instructions:| You are an AI agent. Have a friendly conversation with the user. messages: welcome:| Welcome {!@variables.userPreferredName}! I'm your personal shopping assistant. I can help you: - Find products and check availability - Track your orders - Process returns and refunds - Answer questions about our policies How can I assist you today? error: "Whoops!" ``` ## Config Block The config block contains configuration parameters that define the agent. | Parameter | Description | | :--------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `developer_name` | The Salesforce API name of the agent (max 80 chars). Must start with a letter, contain only alphanumeric and underscores, and can't end with underscore or have consecutive underscores. Must be unique in your org - you can't have two agents with the same `developer_name`. | | ~~`default_agent_user`~~ | Deprecated in this block. Specify `default_agent_user` in the [Access Block](#access-block). | | `agent_label` | Optional. The agent's label, displayed in the UI. Auto-generated from `developer_name` if not provided. | | `description` | Description of the agent's goals and purpose. | | `company` | Optional. Information about your company. | | `role` | Optional. The agent's role. For example, "Help the customer select the perfect gift." | | `agent_version` | The agent's version. Set automatically when you create a new version of your agent. | | `agent_type` | Optional. The type of agent. Currently, allowed values are `AgentforceServiceAgent` (default) or `AgentforceEmployeeAgent`. Set automatically when you create an agent from a template. | | `enable_enhanced_event_logs` | Optional. Indicates whether to enable conversation logging for debugging and monitoring. Allowed values are `True` or `False`. Default: `False`. | | `user_locale` | Optional. User locale setting. | | `runtime` | Optional. Sub-block that controls the agent's runtime behavior, such as streaming, citations, and groundedness checks. See [Runtime Sub-Block](#runtime-sub-block). | | `file_upload` | Optional. Sub-block that controls how the agent handles files uploaded by the customer during a conversation. See [File Upload Sub-Block](#file-upload-sub-block). | ### Example Config Block ```agentscript config: developer_name: "Demo_Agent_1" agent_label: "Demo Agent" description: "This is my demo agent" ``` ## Runtime Sub-Block The `runtime` block is a sub-block of [Config](#config-block) that controls the agent's runtime behavior. | Parameter | Description | | :---------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `streaming` | Controls whether the agent's response is streamed to the client incrementally as it's produced. When `False`, the response is delivered as a single chunk.**When to use:** Leave on (or omit) for interactive chat and voice channels where customers expect the reply to appear progressively. Set to `False` for clients or integrations that only consume a single completed message. | | `thought_chunks` | Controls whether the agent's step-by-step thinking is streamed alongside its responses. When `True`, clients that render "thinking" output can display it during the turn.**When to use:** Enable when your client renders reasoning to the customer or to developers (for example, an "agent is thinking" panel or a debug view). Disable for customer-facing surfaces where exposing internal reasoning is undesirable. | | `citation` | Controls the citation-enrichment post-processing step, which annotates knowledge-based answers with references to their source. Set to `False` to skip citation enrichment.**When to use:** Leave on for knowledge-grounded agents where customers benefit from seeing or clicking through to the source. Disable for channels that can't render citations, or when the extra post-processing latency isn't worth it. | | `groundedness` | By default, Agentforce checks the LLM's responses against source content. This extra step takes some time but reduces the chance of hallucinations. Set to `False` to turn this check off.**When to use:** Leave on for knowledge-heavy agents where reducing hallucinations matters. Disable when you need faster responses and have accepted the tradeoff, or when you've confirmed the check isn't adding value for your use case. | | `reset_to_initial_node` | When `True`, each new customer turn restarts at the start_agent block, instead of resuming where the previous turn left off.**When to use:** Enable for stateless, one-shot Q&A or planner-style agents that should re-plan from scratch every turn. Leave off (the default) for multi-turn flows that need to resume mid-conversation. | ```agentscript config: developer_name: "Demo_Agent_1" runtime: streaming: True thought_chunks: False citation: True groundedness: True reset_to_initial_node: False ``` ## File Upload Sub-Block The `file_upload` block, nested inside `config`, controls how the agent handles files that the customer uploaded during a conversation. | Parameter | Description | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------ | | `mode` | Required. [How the agent handles uploaded](#allowed-mode-values) files. Allowed values are `auto`, `managed`, `disabled`, or `error`. | | `message` | Optional. A message shown to the customer if uploads aren't successful. | ### Allowed `mode` values - **`auto`** — Default file handling. Uploaded files are made available to the agent using standard behavior. - **`managed`** — Use this mode when you want fine-grained control over which uploaded files reach which subagent. This is the mode that pairs with slice syntax on `@system_variables.uploaded_files`, so you can pass a specific batch (for example, `@system_variables.uploaded_files[0:5]`) into an individual subagent. - **`disabled`** — Uploads are rejected without displaying a message to the customer. - **`error`** — Uploads are rejected and treated as an error. If provided, the message in `message` is shown to the customer. If `message` isn't provided, Agentforce generates a message. ```agentscript config: developer_name: "Support_Agent" agent_label: "Customer Support Agent" file_upload: mode: "managed" message: "Something went wrong. Try again." ``` ## Access Block The access block defines the agent's default user. | Parameter | Description | | :------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `default_agent_user` | The agent user's username, which is in the form of an email address. `username` is a field on the [User](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_user.htm) object. You can also see a user's username in Setup. Required for [Agentforce Service agents](https://help.salesforce.com/s/articleView?id=ai.service_agent_setup.htm&type=5). An agent runs in the context of a user, and the user's permissions grant or deny access to Salesforce resources and data. | ```agentscript access: default_agent_user: "service@example.com" ``` ## Variables Block The variables block contains the list of global variables that the agent and script can use. See [Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-variables.md). ```agentscript variables: string_var: mutable string = "hello world" hotel_info: mutable string = "Dreamforce Hotel" ``` You reference variables throughout the script by using the syntax `@variables.`. ## Language Block The language block defines which languages the agent supports. ```agentscript language: default_locale: "en_US" additional_locales: "" all_additional_locales: False ``` For a list of supported languages, see [Agentforce Language Support](https://help.salesforce.com/s/articleView?id=ai.agent_language_support.htm). ## Modality Block The modality block configures agent behavior for a specific modality. The current allowed modality is `voice`. Use `modality voice:` to control how the agent sounds — its voice, speaking speed, pronunciation of specialized terms, and how it handles turn-taking on a live call. ```agentscript modality voice: outbound: persona_id: "" model: parameters: speed: 0.9 ``` By default, a voice agent uses the ElevenLabs v3 Conversational model. - To select a different voice model, see [Configure Voice Models in Agent Script](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice.md). - To see the complete voice catalog, see [Voice Catalog for Agentforce Voice](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice-catalog.md). ### Voice Variables The `voice` variant supports these variables. All variables are optional except `voice_id` when configuring a live voice channel. | Variable | Type | Range | Description | | :------------------------------- | :------- | :-------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `voice_id` | string | — | Unique identifier for the outbound voice (for example, `"UgBBYS2sOqTuMpoF3BR0"`). | | `outbound_speed` | number | 0.5 – 2.0 | Speech rate. `1.0` is normal; lower is slower, higher is faster. | | `outbound_style_exaggeration` | number | 0.0 – 1.0 | How strongly the voice expresses its style. Higher values are more expressive; lower values are flatter and more consistent. | | `inbound_filler_words_detection` | boolean | — | When `True`, filler words (like "um", "uh") in the customer's speech are detected and ignored. | | `inbound_keywords` | block | — | Keyword boost list. Contains a `keywords` sequence of strings that improves recognition for domain-specific terms. | | `pronunciation_dict` | sequence | — | Custom pronunciations for specialized words or names. Each entry has `grapheme` (written form), `phoneme` (phonetic spelling), and `type` (either `"IPA"` or `"CMU"`). | | `outbound_filler_sentences` | sequence | — | Short "thinking" phrases the agent says while an action is running, so the customer doesn't hear dead air. Each entry has a `waiting` list of strings. | | `additional_configs` | block | — | Container for `speak_up_config`, `endpointing_config`, and `beepboop_config`. See [Additional Configs](#additional-configs). | ### Additional Configs The `additional_configs` block groups three sub-configurations that fine-tune turn-taking behavior on a live call. | Sub-config | Variable | Type | Range | Description | | :------------------- | :-------------------------------- | :----- | :------------- | :------------------------------------------------------------------------------------------------------------------------ | | `speak_up_config` | `speak_up_first_wait_time_ms` | number | 10000 – 300000 | How long to wait, in milliseconds, before speaking up for the first time after the customer goes silent. | | `speak_up_config` | `speak_up_follow_up_wait_time_ms` | number | 10000 – 300000 | How long to wait, in milliseconds, before speaking up again if the customer is still silent. | | `speak_up_config` | `speak_up_message` | string | — | The message the agent says when it speaks up. | | `endpointing_config` | `max_wait_time_ms` | number | 500 – 60000 | Maximum time, in milliseconds, to wait for the customer to continue speaking before treating the turn as complete. | | `beepboop_config` | `max_wait_time_ms` | number | 500 – 60000 | Maximum time, in milliseconds, to wait when analyzing an inbound automated tone (like a fax machine or answering system). | ### Full Example ```agentscript modality voice: inbound_filler_words_detection: True inbound_keywords: keywords: - "urgent" - "emergency" voice_id: "UgBBYS2sOqTuMpoF3BR0" outbound_speed: 1.0 outbound_style_exaggeration: 0.5 pronunciation_dict: - grapheme: "Eliquis" phoneme: "ɛlɪkwɪs" type: "IPA" outbound_filler_sentences: - waiting: ["Let me look into that...", "Give me a moment..."] additional_configs: speak_up_config: speak_up_first_wait_time_ms: 10000 speak_up_follow_up_wait_time_ms: 10000 speak_up_message: "Are you still there?" endpointing_config: max_wait_time_ms: 1000 beepboop_config: max_wait_time_ms: 1000 ``` **note:** The voice modality requires a deterministic locale. If your agent uses a `language` block with `adaptive: True`, adaptive language mode is ignored on voice channels and a warning is emitted. Configure a specific `default_locale` in the language block when pairing it with `modality voice`. To branch agent logic based on the customer's current channel at runtime (as opposed to configuring voice-specific behavior here), use the [`@system_variables.current_modality`](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-variables-system.md#current_modality) system variable. ## Connection Block Use the connection block to describe how this agent interacts with outside connections. For instance, this code snippet shows how the agent interacts with [Enhanced Chat](https://help.salesforce.com/s/articleView?id=service.miaw_intro_landing.htm). ```agentscript connection messaging: escalation_message: "One moment while I connect you to the next available service representative." outbound_route_type: "OmniChannelFlow" outbound_route_name: "agent_support_flow" adaptive_response_allowed: True ``` You can use the connection block alongside the [@utils.escalate](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-utils.md#utilsescalate) command. ## Subagent Blocks Use the subagent block to specify the instructions, logic, and actions for a subagent. A subagent block contains a description, a list of actions, and the reasoning instructions. To define a connection to another Agentforce agent in your Salesforce org, see [Connected Subagent Blocks](#connected-subagent-block). ```agentscript subagent Order_Management: description: "Handles order lookup, order updates, and summaries including status, date, location, items, and driver." reasoning: instructions: -> if @variables.order_summary == "": run @actions.lookup_current_order with member_email=@variables.member_email set @variables.order_summary=@outputs.order_summary | Refer to the user by name {!@variables.member_name}. Show their current order summary: {!@variables.order_summary} when conversation starts or if requested. If they want past order info, ask for Order ID and use {!@actions.lookup_order}. actions: lookup_order: @actions.lookup_order with query = ... set @variables.order_summary=@outputs.order_summary set @variables.order_id=@outputs.order_id lookup_current_order: @actions.lookup_current_order with member_email=@variables.member_email set @variables.order_summary=@outputs.order_summary set @variables.order_id=@outputs.order_id actions: lookup_order: description: "Retrieve order details." inputs: query: string outputs: order_summary: string order_id: string target: "flow://SvcCopilotTmpl__GetOrdersByContact" lookup_current_order: description: "Retrieve current order details." inputs: member_email: string outputs: order_summary: string order_id: string target: "flow://SvcCopilotTmpl__GetOrderByOrderNumber" ``` These properties make up a subagent block: - **subagent name**: This value is the name of the subagent that should accurately describe the scope and purpose of this subagent in a few words. Because this value can’t have spaces, use `snake_case` to name the subagent. - **description**: This property contains the description for this subagent. This value should help the agent determine when to use this subagent based on the user’s intent. - **system.instructions** (optional): Override system-level system instructions for this subagent only. By overriding system-level instructions, you can avoid giving conflicting intructions to the LLM, which can cause unexpected agent behavior. You can also change the agent's voice & tone for a specific subagent. See [Avoid Conflicting Instructions with Instruction Overrides](https://developer.salesforce.com/docs/ai/agentforce/guide/patterns/ascript-patterns-system-overrides.md). - **reasoning**: This section contains information sent to the reasoning engine. Its primary properties are instructions and actions. - **reasoning.instructions**: This property contains guidance for the reasoning engine after it has decided that this subagent is relevant to the user's request. The reasoning instructions can be a combination of logic instructions and prompt-based instructions. See [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-instructions.md). - **reasoning.actions**: The list of tools that are applicable for the reasoning engine to use. This list can point to agent actions listed in the higher-level actions section, as well as other functionality available to the reasoning engine (such as transitioning to another subagent, or setting a variable's value). See [Tools (Reasoning Actions)](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-tools.md). - **actions**: This section defines the agent actions available from this subagent. It contains a description of the action, the list of inputs and outputs, and the target location where this action resides. If you want to allow the reasoning engine to use one of these agent actions, you must also point to this action from the `reasoning.actions` section. See [Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-actions.md). ## Connected Subagent Block Use the `connected_subagent` block to define a connection to another Agentforce agent in your Salesforce org. Connected subagents differ from [subagents](#subagent-blocks) that are part of your current agent. A connected subagent represents a complete, independent agent with its own distinct expertise and identity. A connected subagent can contain one or more subagents of its own. You can use a connected subagent in a [reasoning action](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-actions.md#using-actions) to delegate tasks to another Agentforce agent. For more information about using multiple agents in a Salesforce org, see [Multi-Agent Orchestration](https://help.salesforce.com/s/articleView?id=ai.agent_multi_orch.htm&type=5) and [Agent Script in Multi-Agent Solutions](https://help.salesforce.com/s/articleView?id=ai.agent_multi_orch_script.htm&type=5) in Salesforce Help. ```agentscript connected_subagent CRM_Agent: label: "CRM_Agent" target: "agentforce://X00Dfi200000dpFZ_CRM_Agent" loading_text: | Fetching CRM information.... description: "Use this tool for any request about CRM information" # define input variables that you'll use to pass information to the connected agent inputs: EndUserLanguage: string = @variables.EndUserLanguage currentRecordId: string = @variables.currentRecordId ``` ```agentscript start_agent agent_router: model_config: model: "model://sfdc_ai__DefaultEinsteinHyperClassifier" reasoning: actions: go_to_crm: @utils.transition to @connected_subagent.CRM_Agent ``` ```agentscript start_agent agent_router: label: "Agent Router" description: "Welcome the user and determine the appropriate subagent based on user input" reasoning: instructions: -> | Select the best tool to call based on conversation history and user's intent. actions: # transition to a subagent go_to_off_topic: @utils.transition to @subagent.off_topic # Route to the CRM_Agent connected subagent crm_agent: @connected_subagent.CRM_Agent ``` These properties make up a `connected_subagent` block: - **connected_subagent name**: The name used to reference this connected subagent elsewhere in your Agent Script. - **target**: The URI identifying the Agentforce agent (also called the reference agent). This value is filled in when you [connect an agent as a subagent in Agentforce Builder](https://help.salesforce.com/s/articleView?id=ai.agent_multi_orch_connect.htm&type=5). - **label** (optional): A human-readable label for the connected subagent. - **description** (required): Describes the connected subagent's capabilities or when it should be called. This description helps the reasoning engine decide when to delegate to the connected subagent. - **loading_text** (optional): A message shown to the customer while the connected subagent runs. - **inputs** (optional): Values passed to the connected subagent. Each input binding has two sides: - The **left side** (for example, `customer_id`) is a custom, or mutable, variable defined in the connected subagent (that is, in the other Agentforce agent). - The **right side** (for example, `@variables.Customer_Id`) binds the connected subagent's input to a variable in the calling agent. These variables can be either context, or linked variables, or custom, or mutable variables. For example, suppose your input is `customer_id: string = @variables.Customer_Id`. The connected subagent's `customer_id` variable receives the value of the calling agent's `Customer_Id` variable. **note:** In this release, variables are passed in one direction only: from the orchestrator agent to the connected subagent. Variables aren’t passed from a connected subagent back to the orchestrator agent. - **after_response** (optional): Runs after the connected subagent has responded to the user. - **if/then (conditional)** - branch on outcome. - **set** - set the value of a custom, or mutable, variable for the pipeline. - **transition** - delegate control to the next connected subagent. Any script commands placed after the transition are skipped. - **delegate_escalation** (optional): If `True`, allows the connected subagent to escalate to a human representative. Applies only if the connected subagent is in handoff mode. Otherwise, if unspecified, or if the orchestrator agent is in supervision mode, escalation to a human occurs in the orchestrator agent only. ## Start Agent Block The start agent block (called the "Agent Router" in Canvas view) is a subagent that uses the `start_agent` prefix instead of the `subagent` prefix. With every customer utterance, the agent begins execution at this block. The `start_agent` subagent is used to initiate the conversation, and typically determines when to switch to the agent's other subagents. This block handles subagent classification, filtering, and routing. ```agentscript start_agent agent_router: description: "Welcome the user and determine the appropriate subagent based on user input" reasoning: instructions: | You are an agent router for this assistant. Welcome the guest and analyze their input to determine the most appropriate subagent to handle their request. actions: go_to_identity: @utils.transition to @subagent.Identity_Verification description: "Verifies user identity" available when @variables.verified == False go_to_order: @utils.transition to @subagent.Order_Management description: "Handles order lookup, refunds, and order updates." available when @variables.verified == True go_to_faq: @utils.transition to @subagent.General_FAQ description: "Handles various frequently asked questions." available when @variables.verified == True go_to_escalation: @utils.transition to @subagent.Escalation description: "Handles escalation to a human rep." available when @variables.verified == True and @variables.is_business_hours == True ``` For more guidance on how to use the start agent block for subagent routing and filtering, see [Subagent Classification and Routing](https://help.salesforce.com/s/articleView?id=ai.agent_topics_routing.htm) in Salesforce Help. ## Related Topics - [Agent Script Patterns](https://developer.salesforce.com/docs/ai/agentforce/guide/patterns/ascript-patterns.md) - [Agent Script Reference](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-reference.md) - [Configure Models in Agent Script](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-model.md) - [Configure Voice Models in Agent Script](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice.md) # Agent Script Common Patterns This section provides common patterns for building agents with Agent Script. Each pattern focuses on a specific technique you can use to make your agents more reliable and effective. ## About Script and Canvas View These patterns are written in Agent Script as it appears in Script view, so you can easily reuse them in your own agent by copying and pasting. However, the patterns apply in Canvas view, as well. ![Script and Canvas views](https://developer.salesforce.com/media/agent-script/agent-script-patterns-example.png) ## Available Patterns | Pattern | Description | | ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Action Chaining & Sequencing](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-action-chaining.md) | Run multiple actions in a guaranteed sequence | | [Agent Router](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-topic-selector.md) | Set up effective subagent routing in the start_agent block | | [Conditionals](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-conditionals.md) | Use if/else logic to control instructions, actions, and transitions | | [Context Engineering](https://help.salesforce.com/s/articleView?id=ai.agent_context_engineering.htm) | Apply context engineering strategies with your Agentforce agents | | [Fetch Data](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-fetch-data.md) | Run actions to retrieve data before the LLM begins reasoning | | [Filtering with Available When](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-filtering.md) | Control when subagents and actions are visible to the reasoning engine | | [Required Subagent Workflow](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-required-flow.md) | Guarantee users pass through required steps before proceeding | | [Resource References](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-resource-references.md) | Reference variables and actions directly in reasoning instructions | | [System Overrides](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-system-overrides.md) | Override global system instructions to change behavior per subagent | | [Transitions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-transitions.md) | Move execution between subagents with `@utils.transition to` | | [Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-variables.md) | Store and use state effectively across subagents | | [Variables (List)](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-var-list.md) | Store variables in a list, also called a collection. Use a variable from your list just like a custom variable. Use an index to iterate through your list. | ## General Guidance When building agents with Agent Script, keep these principles in mind: - **Start with simple reasoning instructions.** Start with the fewest instructions necessary for an agent to perform as expected. Add instructions as needed as you preview user conversations for different use cases, and then test for regressions between each change. - **Use good names and descriptions.** Clear names for subagents, actions, and variables help your agent make better decisions. - Good names and descriptions are specific, distinct, and clearly related to the agent's task. - Review names and descriptions for other subagents, actions, and variables in your agent to ensure that the names and descriptions are distinct and don't overlap. - Use plain language that end users are likely to use and understand, not technical terms. This makes it easier for the agent to match a user's question or request to a relevant subagent, action, or variable. - Use language consistently throughout. When language is ambiguous, an agent can apply instructions inconsistently or incorrectly. For example, instead of naming an action “Get Client Info” and naming another action "Verify Customer," use the term “customer” in both. - **Add determinism strategically**. Balance natural language instruction with deterministic logic expressions to get the most out of your agent's capabilities. Add logic for business workflows to increase predictable behavior. - **Reference resources directly in reasoning instructions**. "@ mention" references to subagents, actions, and variables to give the LLM explicit guidance. References to resources increase the likelihood that your agent will use the resource as intended. ## Resources - [An Agentforce Guide to Context Engineering](https://help.salesforce.com/s/articleView?id=ai.agent_context_engineering.htm) - [Agent Script Examples](https://developer.salesforce.com/docs/ai/agentforce/ascript-examples.md) - [Agent Script Reference](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-reference.md) - _Trailhead_: [Agent Script Basics](https://trailhead.salesforce.com/content/learn/modules/agent-script-basics) # Agent Script Example: Enforce Subagent Sequencing With Variables To ensure that your agent follows your required workflows through multi-turn conversations, use a step variable to define the current subagent. The agent router selects the subagent based on the step, or state, variable's value. Within a subagent, the LLM evaluates the customer's answer and sets the step variable's next value accordingly. ## When to Use This Pattern Use this pattern when your agent must: - Transition through required subagents in a defined order, where the order can depend on a customer's previous answers. - Handle long multi-turn conversations. For example, to evaluate whether each customer response is complete and valid, returning to the same subagent to ask clarifying questions when needed. - Move to the next subagent only when the current subagent's task is complete. ## Example - Interview Agent The [InterviewAgent.agent](https://resources.docs.salesforce.com/rel1/doc/en-us/static/misc/InterviewAgent.agent) sample screens job applicants by asking required questions in a specific order. Subsequent questions can depend on the applicant's response to the current question. Some responses, such as not holding required credentials, result in interview termination. Each subagent handles one question and decides when the application has provided a sufficient answer. The subagent then sets the `currentInterviewStep` variable appropriately. The agent's `start_agent` router uses the `currentInterviewStep` variable to select the subagent. ![Multi Turn flow diagram](https://developer.salesforce.com/media/agent-script/ascript-example-multiTurn2.png) ## Try This Example 1. Download the [InterviewAgent.agent](https://resources.docs.salesforce.com/rel1/doc/en-us/static/misc/InterviewAgent.agent). 2. In Agent Script, in the upper right, click the **down arrow** next to New Agent and select **New from Script**. 3. Paste the Interview Agent Script code into your new agent. 4. Click your agent to open it, then select **Preview**. 5. Enter a statement like `I'd like to apply for the position` and test your agent. **important:** This agent provides an example of using step variables. It is not a production-ready agent. ## How Routing Works The `start_agent` subagent acts as a router. It checks the value of the `currentInterviewStep` variable and transitions to the corresponding subagent. For example, if the value of `currentInterviewStep` is `Permission`, this transition runs: ```agentscript start_agent agent_router: label: "Agent Router" description: "Welcome the user and determine the appropriate subagent based on user input" reasoning: instructions: -> if @variables.currentInterviewStep == "Permission": transition to @subagent.permission ``` This example uses these values for `currentInterviewStep`: - `Permission`: Confirm candidate has the legal right to work in Wonderland. - `Eligibility`: Ask if the candidate has passed their NCLEX-RN exam. - `Availability`: Identify the candidate's earliest possible start date. - `Competency`: Ask a question about Alice in Wonderland to ensure the candidate has read the book. - `Salary`: Ask about expected salary and compensation preferences. - `Human`: Candidate has passed the screen and questions are passed to a human for follow-up. - `End`: Candidate doesn’t meet qualifications; end the interview. ## How the Step Variable is Updated In each subagent, the agent can call `@utils.setVariables` to update `currentInterviewStep` based on its evaluation of the candidate's response. For example, in the Eligibility subagent, the agent can decide not to change the step variable's value if the customer hasn't fully answered the question. Once the customer has provided a valid answer, the agent can set the step variable to one of these values: - `Availability` - the candidate has passed the NCLEX-RN exam. - `End` - the candidate hasn’t passed the NCLEX-RN exam. ```agentscript subagent eligibility: label: "Eligibility" description: "Ask if the candidate has passed their NCLEX-RN exam." reasoning: instructions: -> | Ask the candidate whether they have passed the NCLEX-RN exam. Request a simple yes or no response and the year passed if available. If they have not passed, acknowledge and explain that passing is required for the role. If the candidate has passed, call {!@actions.setCurrentInterviewStep} with currentInterviewStep set to "Availability". If the candidate is NOT eligible, call {!@actions.setCurrentInterviewStep} with currentInterviewStep set to "End". actions: setCurrentInterviewStep: @utils.setVariables description: "Set the CurrentInterviewStep variable" with currentInterviewStep = ... ``` ## Related Topics - Pattern: [Enforce Required Workflows Through Subagents In Multi Turn Conversations](https://developer.salesforce.com/docs/ai/agentforce/agent-script/patterns/ascript-patterns-multi-turn.md) - Pattern: [Subagent Transitions](https://developer.salesforce.com/docs/ai/agentforce/agent-script/patterns/ascript-patterns-transitions.md) # Agent Script Examples This section provides example Agent Scripts you can use to get started building agents. Each example includes a full script and explains the main concepts it demonstrates. ## Available Examples | Example | Description | | ------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- | | [Customer Support](https://developer.salesforce.com/docs/ai/agentforce/agent-examples/ascript-examples-customer-support.md) | An agent that verifies identity and provides order information | | [Enforce Subagent Sequencing With Variables](https://developer.salesforce.com/docs/ai/agentforce/agent-examples/ascript-examples-multi-turn.md) | A step-based interview agent that enforces question order while handling natural conversation | | [ADL Agent Example - Demystify Jargon with Knowledge](https://developer.salesforce.com/docs/ai/agentforce/agent-examples/ascript-example-rag-jargon.md) | Ensure that your grounded agent understands your organization's evolving jargon without having to update your information sources | ## Agent Script Recipes For more Agent Script examples, see [Agent Script Recipes](https://developer.salesforce.com/sample-apps/agent-script-recipes). [![Agent Script Recipes](https://developer.salesforce.com/media/agent-script/agent-script-recipes.png)](https://developer.salesforce.com/sample-apps/agent-script-recipes) ## Related Topics - [Agent Script Patterns](https://developer.salesforce.com/docs/ai/agentforce/guide/patterns/ascript-patterns.md) - [Agent Script Reference](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-reference.md) # Agent Script Flow of Control Understanding the order of execution and flow of control helps you to design better agents. Agentforce has these main execution paths: 1. First request to an agent 2. Processing a subagent 3. Transitioning between subagents ## First Request to an Agent All requests, including the first request, begin at the agent router, the `start_agent` block. You typically use the `start_agent` subagent to set the initial value of variables, and to perform subagent classification. Subagent classification tells the LLM which subagent to choose based on the current context. See [Start Agent Block](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-blocks.md#start-agent-block). ## Processing a Subagent Agentforce uses a subagent's text instructions, variables, `if`/`else` conditions, and other programmatic instructions to create an LLM prompt. The reasoning instructions are processed sequentially, in top-to-bottom order. While the reasoning instructions can contain programmatic logic and text instructions, the LLM only starts reasoning after it has received the resolved prompt, not while Agentforce is still parsing. If reasoning instructions contain a transition command, Agentforce immediately transitions to the specified subagent, discarding any existing resolved prompt. The final prompt only contains instructions that were resolved from the second subagent. See [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-instructions.md). ### Example: How Agentforce Creates a Prompt from a Subagent Agentforce processes a subagent to create a prompt, which it then sends to the LLM. Consider this subagent. ```agentscript subagent Order_Management: description: "Handles order inquiries." reasoning: instructions:-> set @variables.num_turns = @variables.num_turns + 1 run @actions.get_delivery_date with order_ID=@variables.order_ID set @variables.updated_delivery_date=@outputs.delivery_date | Tell the user that the expected delivery date for order number {!@variables.order_ID} is {!@variables.updated_delivery_date} run @actions.check_if_late with order_ID=@variables.order_ID with delivery_date=@variables.updated_delivery_date set @variables.is_late = @outputs.is_late if @variables.is_late == True: | Apologize to the customer for the delay in receiving their order. after_reasoning: if @variables.num_turns > 5: transition to @subagent.escalate_order ``` Suppose that: - the order ID is `1234` - the current delivery date is `February 10, 2026` - the package is late - the agent has entered this subagent twice in the current session, so `num_turns` is 2 Here's the prompt that Agentforce creates after processing the reasoning instructions: ```agentscript Tell the user that the expected delivery date for order number 1234 is February 10, 2026. Apologize to the customer for the delay in receiving their order. ``` #### How Agentforce Constructs the Prompt To construct the prompt, Agentforce parses the reasoning instructions line by line, following these steps: 1. Initialize the prompt to empty. 2. Increments the global variable `num_turns` from 2 to 3. 3. Run the action `get_delivery_date`. 4. Set the variable `updated_delivery_date` to the value of `outputs.delivery_date`, which was returned by the action. 5. Concatenate this string to the prompt: `Tell the user that the expected delivery date for order number 1234 is February 10, 2026.` 6. Run action `check_if_late`. 7. Set the variable `is_late` to the value of `outputs.is_late`, which was returned by the action. 8. Check whether the value of `@variables.is_late` == `True`. 9. Concatenate this string to the prompt: `Apologize to the customer for the delay in receiving their order.` 10. Process the `after_reasoning` instructions, which don't transition because `num_turns` is 3. 11. Send the prompt to the LLM and return the LLM's response to the customer. ## Transitioning Between Subagents You can transition between subagents from a reasoning action, reasoning instructions, or before and after reasoning blocks. A transition (using [@utils.transition to](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-utils.md#utilstransition-to)) is one-way and control doesn't return to the previous subagent. Agentforce discards any prompt instructions from the previous subagent. Then, Agentforce reads the second subagent from top to bottom. The final prompt contains only instructions from the second subagent. After the second subagent completes, Agentforce waits for the next customer utterance, at which point it returns to the `start_agent` subagent. In this example, we've defined a reasoning action called `go_to_account_help` that transitions to the subagent `account_help`. ```agentscript reasoning: actions: go_to_account_help: @utils.transition to @subagent.account_help description: "When a user needs help with account access" ``` For more about transitions and subagents, see [Referencing a Subagent as a Tool](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-tools.md#referencing-a-subagent-as-a-tool) and the reference documentation for [@utils.transition to](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-utils.md#utilstransition-to). ## Related Topics - [Agent Script Patterns](https://developer.salesforce.com/docs/ai/agentforce/guide/patterns/ascript-patterns.md) - [Agent Script Reference](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-reference.md) # Agent Script Language Characteristics Agent Script is a language designed by Salesforce specifically to build Agentforce agents. This page covers some key characteristics of the language before digging into the specifics. ## Compiled Agent Script is a compiled language. When you save a version of the agent, the script compiles into lower-level metadata that is used by the reasoning engine. ## Determinism Plus Reasoning Agent Script combines deterministic logic with LLM reasoning in a single workflow. This hybrid approach gives you predictable execution where you need it, while preserving the LLM's ability to handle nuanced conversations. - **Logic instructions** (`->`) run deterministically every time. Use them for business rules, running actions, setting variables, and conditional branching. - **Prompt instructions** (`|`) are natural language sent to the LLM. The LLM interprets these instructions and decides how to respond to the customer. See [Flow of Control](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-flow.md), [Agent Script Patterns](https://developer.salesforce.com/docs/ai/agentforce/guide/patterns/ascript-patterns.md), and [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-instructions.md). ## Declarative With Procedural Components Agent Script has elements of both declarative and procedural languages so that you can build an agent that is both predictable and easy to maintain. - A declarative language is a language where you directly _declare_ what you want rather than having to worry about the exact flow step by step. This type of programming language gives you the power to define and customize your agent, but without having to worry about the detailed flow. The basic [Agent Script Blocks](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-blocks.md) resemble a declarative language. - A procedural language is a language where you specify how to execute commands in a specific order. We use elements from procedural languages so that you can specify instructions in logical steps. The logic in [reasoning instructions](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-instructions.md) resemble a procedural language. ## Human-Readable Agent Script is designed to be human-readable so that even non-developers can get a basic understanding of how the agent works. ## Property-Based Agent Script is made up of a collection of properties. Each property is shown as `key: value`. Some properties are multiple lines and some properties contain sub-properties, but the `key` is always before the colon (:) and the `value` is always after the colon. ```agentscript description: "Get account info" ``` The top-level properties are called blocks. For instance, we call this section the config block. ```agentscript config: developer_name: "Demo_Agent_1" agent_label: "Demo Agent" description: "This is my demo agent" ``` ## Indentation and Formatting Agent Script is whitespace-sensitive, similar to languages like Python or YAML, meaning that indentation is used to indicate structure and relationships between properties. To indicate that a value belongs to the previous line’s property, indent with at least 2 spaces or 1 tab. However, you must choose one indentation method and use it consistently throughout the entire script. All lines at the same nesting level must use the same indentation, and mixing spaces and tabs will cause parsing errors. ```agentscript inputs: input_1: string input_2: string ``` To specify logic instructions, use the arrow symbol ( `->` ) followed by indented instructions. ```agentscript instructions: -> if @variables.ready_to_book: run @actions.get_account_info with account_id=@variables.account_id set @variables.hotel_code=@outputs.hotel_code ``` To specify multiline strings in reasoning instructions, descriptions, and system messages, use the pipe symbol ( `|` ). ```agentscript instructions:| Welcome to our service! Please provide details about your request. I'll help you with whatever you need. ``` The pipe symbol can also be used to switch to a prompt from logic-based instructions. ```agentscript reasoning: instructions: -> | You are assessing the customer's timing for making a decision. Follow these rules to determine what to ask: if @variables.Lead_Record.S4STiming != "": | Existing timing data found. Current Timing Value: {! @variables.Lead_Record.S4STiming } Ask: "From what we have, you're looking to make a decision by {! @variables.Lead_Record.S4STiming }. Is that still correct?" Wait for their response before proceeding. ``` See [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-instructions.md) in the Agent Script Reference. ## Accessing Resources You can access resources, such as actions, subagents, and variables, using the `@` symbol. - `@actions.`: References an action. - `@subagent.`: References a subagent. - `@connected_subagent.`: References a connected subagent. - `@variables.`: References a variable. - `@outputs.`: References an action output. To run an action, use the `run` command. Use the `with` command to provide inputs and use the `set` command to store outputs. ```agentscript run @actions.show_great_example with QuestionRecordId=@variables.my_great_question set @variables.my_great_answer = @outputs.AnswerDescription ``` See [Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-actions.md) in the Agent Script Reference. When referencing a variable from within prompt text in reasoning instructions, you must specify the variable within brackets: `{!@variables.}`. For example: ```agentscript | Ask the user this question: {!@variables.my_question} ``` See [Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-variables.md) in the Agent Script Reference. You can specify a subagent as a tool available to the LLM. For more information, see [Tools (Reasoning Actions)](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-tools.md). ## Using Expressions Agent Script uses familiar flow control syntax, such as `if` and `else`. It also uses basic mathematical expressions (`+`, `-`) and comparison expressions (`==`, `!=`, `>`, `<`). You can check for empty values using `is None` and `is not None`. ```agentscript if @variables.count >= 10: run @actions.count_achieved_announcement else: run @actions.count_missed_announcement ``` See [Conditional Expressions](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-expressions.md) and [Supported Operators](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-operators.md) in the Agent Script Reference. ## Comments to Help the Humans You can specify comments in Agent Script with the pound (`#`) symbol followed by the comment. The script ignores any content on the line after the pound symbol. Use this mechanism to document the script within the script. ```agentscript # This is an agent sample script that demonstrates deterministic behavior ``` ## See Also - _Trailhead_: [Programmatic Instructions in Agentforce](https://trailhead.salesforce.com/content/learn/modules/programmatic-instructions-in-agentforce) - _Trailhead_: [Agent Script Basics](https://trailhead.salesforce.com/content/learn/modules/agent-script-basics) # Agent Script Pattern: Action Chaining and Sequencing Run multiple actions in a guaranteed sequence. Action chaining can be implemented in multiple ways depending on when and how you need actions to execute. You can run actions sequentially in instructions, [chain reasoning actions](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-tools.md), or combine actions with transitions and conditionals. ## Why Use This Pattern Action sequencing ensures that one action can trigger another, creating reliable multi-step workflows without relying on the LLM to remember multiple steps. **Pattern Example**: Get the user's order with one action, then immediately check return eligibility for that order in another action. ## Sequential Actions in Instructions Call actions one after another in reasoning instructions. Both run deterministically before the prompt is sent to the LLM. **note:** When you run an action in instructions, you must manually set variables for the inputs and outputs because the action is run before any reasoning takes place. See [Actions Reference](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-actions.md). ```agentscript reasoning: instructions: -> # First action run @actions.lookup_current_order with member_email=@variables.member_email set @variables.order_summary=@outputs.order_summary # Next action run @actions.lookup_current_user with member_email=@variables.member_email set @variables.user_profile=@outputs.profile | Show the user their order summary and welcome them by name. ``` You can also store the output of one action in a variable, then use it as the input to another action, or as part of a subsequent prompt. ## Chained Actions in Reasoning Actions Define a follow-up action that automatically runs when the LLM calls an action. ```agentscript reasoning: instructions: -> | If the user wants information, use {!@actions.my_action}. actions: my_action: @actions.my_action with foo=@variables.Foo set @variables.status = @outputs.status run @actions.other_action set @variables.some_other_result=@outputs.data ``` Whenever the LLM calls `my_action`, the agent automatically runs `other_action` afterwards. ## Run Action Then Transition Run an action and then automatically transition to another subagent. ```agentscript reasoning: instructions: -> | Call {!@actions.validate_user_ready} to check if the user is ready. actions: validate_user_ready: @actions.validate_user_ready with user_id=@variables.user_id set @variables.is_ready=@outputs.ready transition to @subagent.analyze_issue ``` ## Conditional Chain Chain actions conditionally based on the results of previous actions. ```agentscript reasoning: instructions: -> # First action run @actions.check_eligibility with user_id=@variables.user_id set @variables.is_eligible=@outputs.eligible # Condition if @variables.is_eligible == True: # Conditional action run @actions.fetch_offer_details with user_id=@variables.user_id set @variables.offer=@outputs.offer | Present the offer: {!@variables.offer} else: | Explain that the user is not eligible for this offer. ``` ## Tips - **Use sequential instructions for deterministic flows**: When you always want actions to run in a specific order. - **Use variables for action outputs**: If your second action needs an output from the first action, store the first action's outputs in a variable and assign it as an input to the second action. ## Related Topics - Reference: [Actions](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-actions.md) - Reference: [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-instructions.md) - Reference: [Tools (Reasoning Actions)](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-tools.md) # Agent Script Pattern: Agent Router Strategies The agent router is the `start_agent` block that serves as the entry point for your agent. The agent router (also described as the `start_agent` subagent in Agent Script) controls your agent's entry point and routing logic. Keep it focused on essential subagents and use clear descriptions, filtering, and conditional transitions to guide users to the right place. ## Why Use This Pattern Every user utterance begins at the `start_agent` subagent. It welcomes users, classifies intent, routes to appropriate subagents, and controls which subagents are available based on user state. A well-structured agent router ensures that your users get to the right subagent as effectively as possible. **Pattern Example**: A customer service agent's agent router forces unverified users through identity verification, then routes verified users to Order Management, Returns, or Escalation based on their intent. ## Basic Structure The `start_agent` subagent has the same structure as any other subagent. However, it's usually geared towards effective and efficient subagent routing. ```agentscript start_agent agent_router: description: "Welcome the user and determine the appropriate subagent based on user input" reasoning: instructions: -> | Select the best tool to call based on conversation history and user's intent. actions: go_to_orders: @utils.transition to @subagent.Order_Management description: "Handles order lookup, refunds, and order updates." go_to_faq: @utils.transition to @subagent.General_FAQ description: "Handles FAQ lookup and provides answers to common questions." go_to_escalation: @utils.transition to @subagent.Escalation description: "Escalate to a human representative." ``` ## Selective Subagent References Remove references to a subagent if you want the subagent to be accessible only via transitions from other subagents. ## Effective Subagent Descriptions Good descriptions help your agent select the best subagent. Be specific about what each subagent handles. ```agentscript actions: go_to_order: @utils.transition to @subagent.Order_Management description: "Handles order lookup, refunds, order updates, and summarizes status, order date, current location, delivery address, items, and driver name." go_to_returns: @utils.transition to @subagent.Returns description: "Processes return requests for orders within the 60-day return window." go_to_billing: @utils.transition to @subagent.Billing description: "Handles billing inquiries, payment issues, and invoice questions." ``` ## Subagent Gating You can gate and control flow using `available when` filters. See the [Filtering Pattern](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-filtering.md) for examples. ## Deterministic Routing For critical routing decisions, use conditional transitions in instructions instead of relying on the LLM to choose the right flow. See the [Required Subagent Workflow Pattern](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-required-flow.md) for examples. ## Effective Transitions For more on how to effectively transition to another subagent, see the [Transitions Pattern](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-transitions.md). ## Changing the Start Subagent By default, the agent router is defined as the starting subagent in your agent's Agent Script. In other words, this is the subagent that uses the `start_agent` prefix instead of the `subagent` prefix. However, you can define another subagent as the starting subagent instead (in Agent Script, the new subagent becomes the `start_agent` subagent). You can choose to use the agent router to move to subagent classification later in the conversation, or you can remove the agent router from your agent altogether if you want to control subagent routing differently. ## Tips - **Limit subagents**: Start with essential subagents and add more gradually as needed. Fewer subagents means clearer routing decisions for your agent. - **Use the `go_to_` prefix**: Name transition actions with a `go_to_` prefix (for example, `go_to_orders`) so the agent understands they navigate to other subagents. - **Write detailed descriptions**: Use detailed and unique descriptions so the agent knows when to choose a subagent, especially if you have similar subagents. - **Hide subagents based on context**: Use `available when` to control subagent visibility. - **Conditional logic**: Use conditional logic to guarantee that routing occurs before other processing. ## Related Topics - Help Page: [Subagent Classification and Routing](https://help.salesforce.com/s/articleView?id=ai.agent_topics_routing.htm) - Guide: [An Agentforce Guide to Context Engineering](https://help.salesforce.com/s/articleView?id=ai.agent_context_engineering.htm) - Pattern: [Filtering with Available When](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-filtering.md) - Pattern: [Required Subagent Flow](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-required-flow.md) - Pattern: [Transitions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-transitions.md) - Reference: [Start Agent Block](https://developer.salesforce.com/docs/ai/agentforce/ascript-blocks.md#start-agent-block) - Reference: [Flow of Control](https://developer.salesforce.com/docs/ai/agentforce/ascript-flow.md) - _Trailhead_: [Agent Script Basics: Route and Gate Conversations with Agent Script](https://trailhead.salesforce.com/content/learn/modules/agent-script-basics) # Agent Script Pattern: Avoid Conflicting Instructions with Instruction Overrides Override system-level instructions (or "agent-level" instructions in the UI) within specific subagents to change the agent's behavior and persona dynamically. By default, all subagents inherit the agent-level `system.instructions`. When you add a `system` block to a specific subagent, those instructions override the system ones for that subagent only. ## Why Use This Pattern If your agent-level system instructions contradict subagent-level reasoning instructions, your agent can hang or behave unexpectedly. System overrides solve this by explicitly replacing system instructions when needed. Also, system overrides let a single agent adopt different personalities, tones, or behaviors in different contexts—useful when you need the agent to act differently in specific subagents while maintaining consistent behavior elsewhere. **Pattern Example**: An event planner agent normally avoids suggesting alcohol, but for an adult-only party subagent, override the system instructions to allow cocktail recommendations. ## Instruction Hierarchy Agent Script follows this hierarchy when determining which system instructions to use: 1. `Topic-level system instructions (highest priority)` - If a subagent has a `system` block, the agent uses those instructions 2. `Agent-level system instructions (fallback)` - If a subagent has no `system` block, the agent uses the global instructions ## Avoiding Instruction Conflicts When agent-level system instructions contradict subagent-level reasoning instructions, the agent must resolve the conflict, which can cause unexpected behavior. **Problem**: An event planning agent has global instructions "Never suggest alcoholic beverages at a children's party" but a subagent for a children's party with adults wants to suggest champagne in its reasoning instructions. **Solution**: Use a system override to explicitly replace the system instructions for that specific subagent. ```agentscript system: instructions: "You are an event planning assistant. NEVER suggest alcoholic beverages for children's parties or events attended primarily by children." subagent baby_first_birthday: description: "Plan a baby's first birthday celebration with adult guests" system: instructions: "You are an event planning assistant for a baby's first birthday celebration. While the event is for a baby, adult guests are present. You may suggest beverages including champagne for adult guests, while ensuring child-appropriate food and activities." reasoning: instructions: -> | Help plan a memorable first birthday celebration. Consider both the baby's needs and adult guest comfort. Suggest food, drinks, decorations, and activities. ``` ## Creating Multiple Personas Create different personas for different contexts. ```agentscript subagent technical: description: "Technical support specialist" system: instructions: "You are a technical support specialist. Use precise technical terminology, provide step-by-step troubleshooting, ask diagnostic questions, and explain technical concepts clearly. Be patient and thorough." reasoning: instructions: -> | [Technical Support Mode] I am now operating in technical support mode with: - Precise technical language - Diagnostic approach - Step-by-step troubleshooting How can I assist you with technical issues? ``` ```agentscript subagent creative: description: "Creative brainstorming assistant" system: instructions: "You are a creative brainstorming partner. Think outside the box, suggest unconventional ideas, use enthusiastic language, encourage wild ideas, and help explore possibilities without judgment. Be imaginative and supportive." reasoning: instructions: -> | [Creative Mode Activated] I'm now in creative brainstorming mode with: - Think big and bold - No idea too wild - Explore all possibilities What shall we dream up together? ``` ## When to Use Overrides Use overrides when: - **Resolving instruction conflicts**. When agent-level system instructions contradict what a specific subagent needs to do. Conflicting instructions can cause unexpected behavior in agents. - **Different subagents need different tones**. A casual FAQ subagent vs. a formal compliance subagent. Technical experts vs. non-technical users. Casual tone vs. professional and apologetic tone. A billing specialist vs. a technical support specialist. ## Related Topics - Pattern: [Agent Router Strategies](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-topic-selector.md) - Pattern: [Subagent Transitions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-transitions.md) - Reference: [System Block](https://developer.salesforce.com/docs/ai/agentforce/ascript-blocks.md#system-block) - Recipe: [System Instruction Overrides](https://developer.salesforce.com/sample-apps/agent-script-recipes/language-essentials/system-instruction-overrides) # Agent Script Pattern: Enforce Business Rules with Filters Use `available when` to control which subagents or actions are available to the LLM. If the conditions aren't met, the LLM can't access the subagent or reasoning action (also described as a [tool](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-tools.md) in the developer guide). ## Why Use This Pattern When your business conditions aren't met, this pattern allows you to hide the subagent or action entirely, simplifying the LLM's decision-making and enforcing business rules about feature availability. Without filtering, customers might convince the LLM to use features that aren't allowed. Or, the LLM might make reasoning errors during complex workflows and prolonged conversations, due to prompt noise and context drift. See [Required Subagent Workflow](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-required-flow.md) for a related pattern. **Pattern Examples**: - Only enable the `create_return` action when the order is within the return window and verified—otherwise, hide it completely from the agent. - Only enable the `escalate` subagent for verified customers during business hours. ## Filter Subagents Control which subagents are available based on whether the user is verified. ```agentscript start_agent agent_router: description: "Welcome the user and determine the appropriate subagent" reasoning: instructions: -> | Select the best tool to call based on conversation history and user's intent. actions: go_to_order: @utils.transition to @subagent.General_Info description: "Gives general information about products." go_to_order: @utils.transition to @subagent.Order_Management description: "Handles order lookup, refunds, order updates." available when @variables.verified == True go_to_escalation: @utils.transition to @subagent.Escalation description: "Handles escalation to a human rep." available when @variables.verified == True and @variables.is_business_hours == True ``` In this example: - All users can access General Info. - Verified users can be routed to the Order Management. - Escalation requires verification **and** valid business hours. ## Filter Actions Make actions available only when business rules are satisfied. ```agentscript reasoning: instructions: -> | Refer to the user by their name {!@variables.member_name}. Show the user their order summary: {!@variables.order_summary}. If the user wants to make a return, confirm their order ID and call {!@actions.create_return}. If returns are not eligible, explain why. actions: create_return: @actions.create_return available when @variables.order_return_eligible == True and @variables.order_id != None ``` **note:** Keep in mind that the LLM can call any **available** reasoning action, even if you don’t explicitly tell it to. ## Tips - **Protect against customer manipulation**: Filter business-sensitive features. Don't only rely on prompt engineering. - **Use parentheses when nesting `and` / `or` conditions**: Using parentheses makes it clear which operations are evaluated first, and keeps your script maintainable. ## Related Topics - Pattern: [Required Subagent Workflow](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-required-flow.md) - Reference: [Tools (Reasoning Actions)](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-tools.md) - Reference: [Conditional Expressions](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-expressions.md) - Reference: [Start Agent Block](https://developer.salesforce.com/docs/ai/agentforce/ascript-blocks.md#start-agent-block) - _Trailhead_: [Programmatic Instructions in Agentforce: Enforce Business Rules with Variables and Action Filters](https://trailhead.salesforce.com/content/learn/modules/programmatic-instructions-in-agentforce) # Agent Script Pattern: Enforce Required Workflows for a Subagent Use conditional transitions to guarantee users pass through required steps before accessing other features. Use conditional transitions at the top of your instructions to force users through required steps. Unlike filtering with `available when`, these transitions execute immediately and guarantee the routing behavior. ## Why Use This Pattern - Use [filtering](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-filtering.md) (`available when`) when you want to remove options. - Use the required flow pattern (also described as a "conditional transition") when users must complete a step before anything else occurs. - Use [Enforce Required Workflows Through Subagents In Multi Turn Conversations](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-multi-turn.md) to enforce step-by-step sequencing across conversation turns. This pattern ensures a required workflow through subagents, where the next subagent depends on a customer's response to a previous subagent. | Approach | When to Use | | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------- | | `available when` | Control which reasoning actions are available; LLM chooses among them | | Conditional transition | Require users to complete a step; no LLM choice | | [Enforce Required Workflows Through Subagents In Multi Turn Conversations](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-multi-turn.md) | Enforce step-by-step sequencing through subagents while handling multiple conversation turns in each subagent | For critical flows like identity verification, a conditional transition in instructions is more reliable than `available when` filtering alone. While filtering restricts options, it doesn’t enforce workflows. For example, instead of prompting the user to verify their identity, the agent can exclusively choose options that don’t require user verification. A conditional transition guarantees the workflow before any reasoning takes place. **Pattern Examples**: - Force unverified users through identity verification before they can access order management, returns, or any other sensitive subagents. - Ensure order return subagents ask the correct next question based on previous answers, and that all required questions are asked. ## Required Flow for All Subagents To require a subagent flow before a user can move to any other subagents, in the agent router, place a conditional transition at the top of your instructions. If the condition is met, the transition happens immediately before any other processing. ```agentscript start_agent agent_router: description: "Welcome the user and route to the appropriate subagent" reasoning: instructions: -> # Check for condition if @variables.verified == False: # Required transition to a subagent transition to @subagent.Identity # Subsequent processing that only occurs # if condition ISN'T met… | Select the best tool to call based on conversation history and user's intent. actions: go_to_orders: @utils.transition to @subagent.Order_Management description: "Handles order lookup, refunds, and order updates." go_to_faq: @utils.transition to @subagent.General_FAQ description: "Handles FAQ lookup and common questions." go_to_escalation: @utils.transition to @subagent.Escalation description: "Escalate to a human representative." ``` Unverified users are immediately routed to the Identity subagent. No subagent classification takes place and no prompt is sent to the LLM. After the user completes verification with the Identity subagent, the process starts over. Because the Verified variable is now set to True, the conditional is satisfied. The agent can proceed through the remaining instructions and the other subagents in the agent router are available to the user. ## Required Flow for a Single Subagent This pattern works in any subagent, not just the agent router. Use it when an individual subagent requires a prerequisite. ```agentscript subagent Order_Management: description: "Handle order inquiries and updates" reasoning: instructions: -> # Check for condition if @variables.order_id is None: # Required transition to a subagent transition to @subagent.Order_Lookup # Subsequent processing that only occurs # if condition ISN'T met… | Help the user with their order {!@variables.order_id}. ``` ## Use Step Variables to Select a Subagent This pattern works in any subagent, particularly in the agent router. Use it to enforce a complex subagent workflow throughout multi-turn conversations. See [Agent Script Example: Use Step Variables to Enforce Subagent Workflows](https://developer.salesforce.com/docs/ai/agent-examples/ascript-examples-multi-turn.md). ## Tips - **Use the `go_to_` prefix**: Name transition actions with a `go_to_` prefix (for example, `go_to_orders`, `go_to_faq`) so the LLM understands they navigate to other subagents. - **Place required flows first**: Put conditional transitions at the top of instructions so they execute before any other instructions. If the agent transitions to another subagent before reasoning, no prompt is sent to the LLM. Prior instructions aren't used or preserved, so executing them just increases latency and (in the case of running an action) can incur costs. - **Use descriptive names**: Avoid generic names like `tool1` or `action2`; use names that describe the destination or purpose. ## Related Topics - Pattern: [Conditionals](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-conditionals.md) - Pattern: [Transitions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-transitions.md) - Pattern: [Filtering with Available When](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-filtering.md) - _Trailhead_: [Agent Script Basics: Route and Gate Conversations with Agent Script](https://trailhead.salesforce.com/content/learn/modules/agent-script-basics) # Agent Script Pattern: Enforce Required Workflows Through Subagents In Multi Turn Conversations Ensure your agent adheres to your subagent sequencing rules through multi-turn conversations, even when your sequencing rules are complex. Use a step variable to control which subagent the agent router selects. Within a subagent, allow the agent to evaluate the customer's answer and set the step variable for the next step. ## Why Use This Pattern Use this pattern when: - The agent must ask a long sequence of required questions and validate each answer before moving to the next question - The next question asked depends on the previous question's answer - The agent may spend many turns in a single subagent, for example clarifying a specific salary requirement or explaining certification equivalency. ### When Not to Use This Pattern Use the simpler pattern in [Enforce Required Workflows for a Subagent](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-required-flow.md) when you only need a single prerequisite gate, such as verification before routing, or a one-subagent prerequisite like collecting `order_id` before order help. ## Example: Step-Driven Interview Questions In this pattern, `start_agent` uses the `currentInterviewStep` variable to select the current subagent. In each subagent, the agent asks the customer a specific set of questions. Based on the customer's response, the agent sets the value of the `currentInterviewStep` variable, controlling what the next subagent in the sequence will be. For example, in the `permission` subagent, the agent asks the customer whether they have legal permission to work in the region. - If the customer **does** have permission, the agent sets `currentInterviewStep` to `Eligibility`, ensuring the agent router routes to the `eligibility` subagent. - If the customer **doesn't** have permission, the agent sets `currentInterviewStep` to `End`, ensuring the agent router routes to the `end_interview` subagent. ```agentscript start_agent agent_router: label: "Agent Router" description: "Welcome the user and determine the appropriate subagent based on user input" reasoning: instructions: -> if @variables.currentInterviewStep == "Permission": transition to @subagent.permission if @variables.currentInterviewStep == "Eligibility": transition to @subagent.eligibility if @variables.currentInterviewStep == "Availability": transition to @subagent.availability if @variables.currentInterviewStep == "End": transition to @subagent.end_interview subagent permission: label: "Permission" description: "Confirm the candidate has the legal right to work in Wonderland." reasoning: instructions: -> | Confirm whether the candidate has the legal right to work in Wonderland. Ask a clear yes or no question and allow the candidate to provide context if needed. If the candidate confirms eligibility, acknowledge and advise the next step. If the candidate is not eligible or refuses to answer, advise that the role requires work authorization. If the candidate is eligible, call {!@actions.setCurrentInterviewStep} with currentInterviewStep set to "Eligibility". If the candidate is NOT eligible, call {!@actions.setCurrentInterviewStep} with currentInterviewStep set to "End". actions: setCurrentInterviewStep: @utils.setVariables description: "Set the CurrentInterviewStep variable" with currentInterviewStep = ... ``` ## Tips - **Keep one responsibility per subagent**: Design each subagent to validate one required answer, then move to the next step. - **Use explicit step names**: Use clear values like `permission`, `eligibility`, and `availability` so routing remains easy to read and maintain. - **Let subagents own completion logic**: The subagent should decide when an answer is satisfactory and continue asking follow-ups until it is. ## Related Topics - Pattern: [Transitions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-transitions.md) - Pattern: [Conditionals](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-conditionals.md) - Pattern: [Enforce Required Workflows for a Subagent](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-required-flow.md) - _Trailhead_: [Agent Script Basics: Manage State Across a Multi-Turn Conversation](https://trailhead.salesforce.com/content/learn/modules/agent-script-basics) # Agent Script Pattern: Fetch Data Before Reasoning Run actions to retrieve data before the LLM begins reasoning. Place action calls at the top of your reasoning instructions to fetch data before the prompt is constructed. This ensures the LLM has access to current, accurate information when generating responses. ## Why Use This Pattern Fetching before reasoning ensures the LLM has accurate, current data. For example, you can store the output of an action in a variable and use it to personalize instructions. Or you can create a filter based on the variable to refine the prompt that's sent to the LLM. Actions inside reasoning instructions execute **before** the prompt is sent to the LLM. **Pattern Example**: Look up the user's current order before the conversation starts so the agent can greet them with their order status and personalized recommendations. ## Basic Pattern ```agentscript reasoning: instructions: -> # Check if data has been fetched if @variables.order_summary == "": # If not, fetch data with an action # (and store results in a variable) run @actions.lookup_current_order with member_email=@variables.member_email set @variables.order_summary=@outputs.order_summary # Reference the variable in the prompt | Refer to the user by name {!@variables.member_name}. Show them their current order summary: {!@variables.order_summary}. ``` The pattern: 1. Check if data has already been fetched 2. If not, run the lookup action 3. Store results in a variable 4. Reference the variable in the prompt ## Fetch and Validate Fetch data and immediately check it to determine what options to present. ```agentscript reasoning: instructions: -> if @variables.order_summary == "": run @actions.lookup_current_order with member_email=@variables.member_email set @variables.order_summary=@outputs.order_summary | If user wants to make a return: if @variables.order_summary.days_since_order <= 60: set @variables.return_eligibility = true | Offer to process return using {!@actions.create_return}. else: | Politely explain the return period has expired. ``` ## Tips - **Avoid unnecessary calls**: Always check if data exists (`if @variables.data == ""`) before making a call to fetch data to avoid running actions unnecessarily. ## Related Topics - Reference: [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-instructions.md) - Reference: [Actions](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-actions.md) - Reference: [Variables](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-variables.md) - _Trailhead_: [Programmatic Instructions in Agentforce: Give Your Agent More Information with Flows, Actions, and Permissions](https://trailhead.salesforce.com/content/learn/modules/programmatic-instructions-in-agentforce) # Agent Script Pattern: Reference Resources Directly in Reasoning Instructions Reference subagents, actions, and variables directly in the prompt text of your reasoning instructions. Use @ mentions and the {curly brace} syntax to reference variables and reasoning actions directly. ## Why Use This Pattern Reference subagents, actions, and variables directly in your reasoning instructions using special syntax. Use @ mentions and the curly brace syntax to reference variables and actions directly in your prompt text. **Pattern Example**: Display a personalized order summary by referencing variables like order name, date, and status, and guide the user to the `lookup_order` action or `Returns` subagent when they need more help. ## Reference Syntax - **Subagents**: `{!@subagents.}` - **Actions**: `{!@actions.}` - **Variables**: `{!@variables.}` ## Reference Variables in Output Reference variables directly to include specific data in the response. ```agentscript reasoning: instructions: -> | Refer to the user by preferred name {!@variables.preferred_name}. Output a summary to the user in the following format: Order Name: {!@variables.order_name} Order Date: {!@variables.order_date} Order Status: {!@variables.order_status} ``` ## Reference Actions in Instructions Reference actions directly to tell the LLM which reasoning action to use. ```agentscript reasoning: instructions: -> | If the user wants information about a past order, ask for the Order ID or Restaurant Name and use {!@actions.lookup_order}. If the user asks for a service agent or seems upset, go to {!@actions.go_to_escalation}. If the user wants to make a return, confirm their order ID and call {!@actions.create_return}. ``` ## Combine Variable and Action References Use both types of references together for complete, specific instructions. ```agentscript reasoning: instructions: -> | Refer to the user by their name {!@variables.member_name}. Show the user their current order summary: {!@variables.order_summary} at the start of the conversation or if they specifically request it again. If the user wants to make a return, confirm their order ID and call {!@actions.create_return}. If returns are not eligible ({!@variables.order_return_eligible} is False), explain that the order is not eligible for return. ``` ## Conditional Output with References Use references inside conditional prompts as well. ```agentscript reasoning: instructions: -> if @variables.loyalty_tier == "Gold": | Thank the customer for being a Gold member. Their current points balance is {!@variables.points_balance}. if @variables.loyalty_tier == "Platinum VIP": | Welcome back, valued Platinum VIP member {!@variables.member_name}! You have {!@variables.points_balance} points available. ``` ## Tips - **Reference resources when clarity is required**: In general, the agent can figure out which resource to use. In cases where you have many actions, for example, add a reference to help the agent pick the right one. Direct references are a stronger signal to the LLM, so it's more likely to select the right variable, action, or subagent. ## Related Topics - Reference: [Tools (Reasoning Actions)](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-tools.md) - Reference: [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-instructions.md) - Reference: [Variables](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-variables.md) - Reference: [Actions](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-actions.md) # Agent Script Pattern: Subagent Transitions Move execution from one subagent to another using the `@utils.transition to` command. Transitions move execution from one subagent to another. You can expose them as reasoning actions (sometimes described as [tools](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-tools.md) in the developer guide) for the LLM to select, execute them deterministically with conditionals, or chain them after actions complete. ## Why Use This Pattern Transitions route users to specialized subagents based on their needs. They're one way—when a transition occurs, Agentforce discards any prompt from the current subagent and processes the new subagent instead. **Pattern Examples**: When a user asks about a refund, transition them from the General FAQ subagent to the specialized Returns subagent. Or, after validating a user's identity, automatically transition to the Order Management subagent to continue the conversation. ## Reasoning Transitions The following transitions can occur based on the LLM's reasoning. Deterministic transitions are described in the next section. ### Transitions in Reasoning Actions Expose transitions as reasoning actions (tools) that the LLM can choose to use. ```agentscript start_agent agent_router: description: "Welcome the user and determine the appropriate subagent" reasoning: instructions: -> | Welcome the user and analyze their input to determine the most appropriate subagent to handle their request. actions: go_to_order: @utils.transition to @subagent.Order_Management description: "Handles order lookup, refunds, order updates." go_to_faq: @utils.transition to @subagent.General_FAQ description: "Handles FAQ lookup and common questions." go_to_escalation: @utils.transition to @subagent.Escalation description: "Escalate to a human representative." ``` ### Filtered Transitions Combine transitions with `available when` to control which subagents are accessible. ```agentscript reasoning: actions: go_to_identity: @utils.transition to @subagent.Identity description: "Verifies user identity" available when @variables.verified == False go_to_order: @utils.transition to @subagent.Order_Management description: "Handles order management" available when @variables.verified == True ``` See the [Filtering Pattern](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-filtering.md). ### Transitions in Instructions When exposing transitions as reasoning actions (tools), reference them in your prompt so the LLM knows when to use them. ```agentscript reasoning: instructions: -> | If the user asks for a service agent or seems upset, go to {!@actions.go_to_escalation}. actions: go_to_escalation: @utils.transition to @subagent.Escalation description: "Escalate if requested or needed." ``` ## Deterministic Transitions The following transitions occur deterministically based on your instructions. Reasoning transitions are described in the previous section. **note:** Transitions in reasoning instructions don’t use the `@utils.` prefix. ### Conditional Transitions in Reasoning Instructions Deterministically route users based on state or business rules. ```agentscript reasoning: instructions: -> if @variables.loyalty_tier == "Platinum VIP": transition to @subagent.vip_support ``` The transition happens before the LLM processes any other instructions. ### Transition After Action Chain a transition after an action completes. ```agentscript reasoning: instructions: -> | Call {!@actions.validate_user_ready} to check if the user is ready. actions: validate_user_ready: @actions.validate_user_ready with user_id=@variables.user_id transition to @subagent.analyze_issue ``` ## Tips ### Reasoning Transition Tips - **Use descriptive subagent names**: Names should clearly indicate the subagent's purpose. - **Provide clear descriptions**: Help the LLM understand when to use each transition. - **Use the `go_to_` prefix**: Name transition actions with a `go_to_` prefix (for example, `go_to_orders`) so the agent understands they navigate to other subagents. - **Reference transitions in prompt**: When exposing transitions as reasoning actions, you can reference them in your prompt (for example, `{!@actions.go_to_escalation}`) so the LLM knows when to use them. ### Deterministic Transition Tips - **Use deterministic transitions sparingly**: Only when you need guaranteed routing; otherwise let the LLM choose. - **Place transitions first**: When using conditional transitions, put them at the top of instructions so they execute before any other instructions. If the agent transitions to another subagent before reasoning, no prompt is sent to the LLM. Prior instructions aren't used or preserved, so executing them just increases latency and (in the case of running an action) can incur costs. - **Avoid transition loops**: Ensure your subagent flow doesn't create infinite loops. For example, you don't want to introduce some logic that causes a transition from subagent A to subagent B but also causes a transition from subagent B back to A, and then repeat. ## Related Topics - Pattern: [Agent Router](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-topic-selector.md) - Pattern: [Required Subagent Flow](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-required-flow.md) - Reference: [Utils](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-utils.md) - Reference: [Tools (Reasoning Actions)](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-tools.md) - Reference: [Flow of Control](https://developer.salesforce.com/docs/ai/agentforce/ascript-flow.md) # Agent Script Pattern: Using Conditionals Use conditionals to deterministically control agent behavior based on variable values. Conditionals evaluate before the prompt reaches the LLM. ## Why Use This Pattern Conditionals let you make deterministic decisions about which instructions are included in the prompt, which actions run, or which subagents to transition to. Conditionals don't rely on LLM interpretation. **Pattern Example**: Show Gold members a thank-you message and their points balance, while Platinum VIP members see an exclusive welcome with additional perks. ## Conditional Instructions Customize the prompt based on variable values. ```agentscript reasoning: instructions: -> | Refer to the user by name {!@variables.member_name}. if @variables.loyalty_tier == "Gold": | Thank the customer for being a Gold member. if @variables.loyalty_tier == "Platinum VIP": | Thank the customer for being a Platinum VIP member. ``` Only the relevant instruction is included in the prompt sent to the LLM. - Prompt sent to LLM if the customer’s name is Jo Richards and they're a VIP member: `Refer to the user by Jo Richards. Thank the customer for being a Platinum VIP member.` - Prompt sent to the LLM if the customer’s name is Jane Smith and they're a Gold member: `Refer to the user by Jane Smith. Thank the customer for being a Gold member.` ## Conditional Actions Run actions only when specific conditions are met. In this example, the agent only looks up the current order if we don't have an order summary, improving response time and reducing system usage. ```agentscript reasoning: instructions: -> if @variables.order_summary == "": run @actions.lookup_current_order with member_email=@variables.member_email set @variables.order_summary = @outputs.order_summary | Show the user their order summary: {!@variables.order_summary}. ``` ## Conditional Transitions Route users to different subagents based on conditions. ```agentscript reasoning: instructions: -> if @variables.loyalty_tier == "Platinum VIP": transition to @subagent.vip_support ``` The transition happens immediately, before the LLM processes any other instructions. See [Required Subagent Flow](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-required-flow.md) for related patterns. ## If/Else Logic Handle mutually exclusive conditions with `if` and `else` logic. ```agentscript reasoning: instructions: -> if @variables.order_summary.days_since_order <= 60: set @variables.return_eligibility = True | Offer to process return using {!@actions.create_return}. else: | Politely explain the return period has expired. ``` ## Multiple Conditions Keep in mind that you can combine conditions using `and` or `or`. ```agentscript reasoning: instructions: -> if @variables.verified == True and @variables.is_business_hours == True: | You can escalate to a live representative if needed. ``` ## Tips - **Initialize variables for reliable checks**: It's typically a good practice to give variables default values (for example, `= ""` or `= False`) so conditional checks work correctly. - **Use `is None` for null checks**: Use `@variables.value is None` to check whether a variable has no value assigned. This check is different from checking for an empty string (`@variables.value == ""`), for example. The `== ""` expression checks for an empty string (which is a valid assignment), whereas `is None` checks for an unassigned value. - **Use parentheses to control evaluation order**: Use parentheses `()` to explicitly group the conditionals you want evaluated together. For example, an action could have this `available when` condition: ```agentscript available when @variables.customerType == "Valued" and @variables.QualificationEnabled == True and (@variables.HasSalesInterest == True or @variables.WantsMeeting == True) and @variables.QualificationFlowStep != "COMPLETE" ``` ## Related Topics - Pattern: [Required Subagent Flow](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-patterns-required-flow.md) - Reference: [Conditional Expressions](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-expressions.md) - Reference: [Supported Operators](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-operators.md) - Reference: [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-instructions.md) - _Trailhead_: [Programmatic Instructions in Agentforce: Use Conditional Logic to Send the Right Prompt for Each Context](https://trailhead.salesforce.com/content/learn/modules/programmatic-instructions-in-agentforce) # Agent Script Pattern: Using List Variables With [list variables](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-variables-list.md) (also called collection variables), your agent can store and iterate over a collection of values. For example, create a list of questions that an interview agent must ask, or a list of objects to store an action's output. A list can store any supported type, such as strings, booleans, numbers, or objects. Use a list item anywhere you use a [custom variable](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-variables.md). ## Reference an Item in a List To reference an item in a list, use `json_path` or bracket `[]` syntax. `json_path` syntax returns the value enclosed in `[""]` characters, while `[]` syntax returns the raw value. | Syntax | Example | Example Return Value | | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | -------------------- | | `@variables.[].data.` | The name of the fourth account in a list of accounts:
`@variables.all_accounts[3].data.Name` | `Acme Corp` | | `json_path(@variables., "$[].data.")` | The name of the fourth account in a list of accounts:
`json_path(@variables.all_accounts, "$[3].data.Name")` | `["Acme Corp"]` | Lists are zero-indexed. To get the first item in your list, use `[0]`. ## Pattern: Iterate Through a List with an Index Variable Advance through a list one item per turn by using an index variable to track the current list item. Increment the variable in `after_reasoning` to ensure determinism — `after_reasoning` is run deterministically (it isn't sent to the LLM), and is guaranteed to run every turn (the subagent has no transitions). ### How This Pattern Works This example shows a TestList1 subagent that asks one question per turn, and a Variables block that declares the index and question variables. The subagent's responsibilities are spread across two sub-blocks: - **`reasoning.instructions:`** runs first. It reads the question specified by the current index variable, then builds the prompt sent to the LLM. - **`after_reasoning:`** runs after the LLM returns its response. It compares the current index to the length of the questions list, then increments the index if more questions remain. ### Why Use This Pattern Use this pattern when: - The agent must walk through a list in order (checklist steps, survey questions, records) and reference exactly one item in each turn's prompt. - Ordering must be deterministic, not subject to LLM reasoning. ```agentscript variables: question_index: mutable number = 0 description: "Zero-based index of the current question." CompetencyQuestions: mutable list[string] = ["Have you passed your certification exam?", "Do you have the legal right to work here?", "Tell me about your past jobs.", "What is your most important accomplishment?"] description: "List of competency screening questions to ask." subagent TestList1: label: "TestList1" description: | Ask the candidate the current question from CompetencyQuestions. reasoning: instructions: -> # On the first turn, this line resolves to "Tell the user that this is question 1 of 4". | Tell the user that this is question {!@variables.question_index + 1} of {!len(@variables.CompetencyQuestions)}. # On the first turn, question_index is 0, so this line resolves to "Then, ask this question: Have you passed your certification exam?" | Then, ask this question: {!@variables.CompetencyQuestions[@variables.question_index]} # The index variable is incremented in after_reasoning. after_reasoning: # Compare the current index to the length of the list to see if we're done or not if @variables.question_index + 1 < len(@variables.CompetencyQuestions): # if we're not done, increment the index set @variables.question_index = @variables.question_index + 1 ``` ### Agent Output for This Pattern This agent preview shows how the pattern works. ![Output of list pattern 1 agent](https://developer.salesforce.com/media/agent-script/list-pattern-1.jpg '{"class": "image-sm"}') **note:** This pattern doesn't show how to handle the workflow after the agent asks the last question, because that logic is agent-specific. Your agent can transition to the next subagent, set a state variable so the subagent isn't called again, or provide specific instructions in the agent router. ## Pattern: Access a Field from a List of Objects This example shows how to read fields from a list of objects by using both `json_path` and bracket `[]` syntax. The subagent calls an action that returns a list of Account objects, stores the returned list in the `all_accounts` list variable, and extracts two account names from the list. ### Why Use This Pattern Use this pattern when: - An action returns a list of objects (accounts, cases, orders) and later reasoning or logic needs to reference specific field values. - The customer uploads a complex list, and you reference specific values. ```agentscript variables: all_accounts: mutable list[object] description: "List of Account objects returned by the Get_All_Accounts action." label: "all_accounts" third_account_name: mutable string description: "Name of the third account in all_accounts (index 2)." fourth_account_name: mutable string description: "Name of the fourth account in all_accounts (index 3)." subagent Get_All_Accounts: label: "Get All Accounts" description: | Runs an action to get all of the org's accounts, then stores two specific account names. reasoning: instructions: -> | Run {!@actions.Get_All_Accounts} actions: Get_All_Accounts: @actions.Get_All_Accounts with RequestReason = ... # Capture the action's list output into a persistent variable. set @variables.all_accounts = @outputs.Accounts after_reasoning: # json_path — returns the JSON representation of the match, e.g. ["Acme Corp"]. set @variables.third_account_name = json_path(@variables.all_accounts, "$[2].data.Name") # Dot-access — returns the bare string, e.g. Acme Corp. set @variables.fourth_account_name = @variables.all_accounts[3].data.Name actions: Get_All_Accounts: label: "Get All Accounts" description: | Returns a list of every Account object on the org. target: "flow://Get_All_Accounts" inputs: # Placeholder input. Agentforce actions must declare at least one input, # even when the underlying flow doesn't use it. RequestReason: string label: "RequestReason" description: "Placeholder input to satisfy the Agentforce action requirement. Not used by the flow." is_required: False outputs: Accounts: list[object] label: "Accounts" complex_data_type_name: "lightning__recordInfoType" is_displayable: True filter_from_agent: False ``` ## Tips - Lists are zero-indexed. To reference the first item, use `[0]`. - `json_path` returns the matched value wrapped in `[""]` characters (for example, `["Acme Corp"]`), while bracket `[]` syntax returns the raw value (for example, `Acme Corp`). Choose the syntax that matches the value you want to store or display. - To advance through a list deterministically, increment the index variable in `after_reasoning` instead of `reasoning.instructions`, so the update isn't left to the LLM. - Use `len(@variables.)` to check a list's length before you reference an item, so your agent doesn't index past the end of the list. ## Related Topics - Reference: [Variables](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-variables.md) - Reference: [List Variables](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-variables-list.md) # Agent Script Pattern: Using Variables Effectively Variables store information about the agent's current state across subagents and turns. ## Why Use This Pattern Variables help you track state that affects agent behavior, pass data among subagents, use data in conditionals, and show specific information to users. Use them strategically to track important information, but avoid over-constraining your agent by storing every piece of data. Use variables for: - **Storing values for reuse**: Data for conditionals, inputs to actions in other subagents, or to show to users. - **Storing action outputs**: Results from actions that you need in conditional or other deterministic workflows. - **`available when` clauses**: Conditions to determine which actions, subagents, and prompts are available. ```agentscript variables: member_name: mutable string description: "The name of the member for personalized greetings" verified: mutable boolean = False description: "Whether the user's identity has been verified" order_summary: mutable string = "" description: "Summary of the user's current order" ``` **Pattern Example**: Store the user's verification status in a variable so all subagents can check whether the user is verified before showing sensitive information. ## Initialize Variables Initialize variables with sensible defaults so conditional checks work correctly. ```agentscript variables: # Use empty string for text that is fetched later order_summary: mutable string = "" # Use False for flags that start negative verified: mutable boolean = False # Leave uninitialized for values that must be provided member_email: mutable string ``` ## Good Variable Descriptions Clear descriptions help the agent use variables correctly. ```agentscript variables: is_business_hours: mutable boolean = False description: "Whether it is business hours. Used to determine if the agent can escalate to a live representative." loyalty_tier: mutable string description: "The customer's loyalty tier (Standard, Gold, or Platinum VIP). Used for personalized greetings and feature access." ``` ## Store Action Outputs Store action outputs in variables if you need to use them in conditional expressions, as required inputs to another action, or for other deterministic workflows. ```agentscript reasoning: instructions: -> run @actions.lookup_current_order with member_email=@variables.member_email set @variables.order_summary=@outputs.order_summary set @variables.order_id=@outputs.order_id | Show the user their order: {!@variables.order_summary} ``` ## Share Information Between Subagents You can use variables to share information, or state, between subagents. For example, to share the current temperature between all subagents in an agent, run the `Get_Current_Weather_Data` action and store the value of the temperature output in the global temperature variable. ```agentscript reasoning: instructions: -> # always get the current weather data run @actions.Get_Current_Weather_Data with city=@variables.user_city # set the variable "temperature" with the # current temperature so that other subagent has that info set @variables.temperature = @outputs.temperature_celsius ``` ## Let the LLM Set Variables with User-Entered Information (Slot Filling) Use `...` to indicate that the LLM should use reasoning to set a variable's value. For example, the LLM can ask the user for their first and last name, then use the `capture_user_info` tool to set those values in the variables `first_name` and `last_name`. Using reasoning to set a variable's value is called slot filling. For simple workflows, the LLM can figure out which actions to call based on the action's description and name. In this example, we explicitly reference `{!@capture_user_info}` in the instructions to be sure the LLM stores the user information. ```agentscript reasoning: instructions: -> Ask the user for their full name. Then, use {!@actions.capture_user_info} to set the value of the user's first and last name. actions: capture_user_info: @utils.setVariables with first_name = ... with last_name = ... description: "Set the user's name as variables" ``` **note:** You can use slot-filling for top-level action inputs (which are called by the LLM), but not for chained action inputs (because they’re run deterministically). ## Tips - **Name variables clearly**. Use descriptive names like `order_return_eligible` not `flag1`. - **In reasoning instructions, assign variables to action inputs and outputs**. When you run an action in reasoning instructions, you must manually set variables for the inputs and outputs because the action is run before any reasoning takes place. - **In reasoning actions, use variables as action inputs sparingly**. Actions are made available to the agent when the agent has all the relevant action inputs, so specifying variables for too many inputs can cause the agent to select actions inconsistently. When you don't specify a variable as input, the agent can usually decide the best input. Specify variables as inputs only when necessary, based on testing. - **Store action outputs in variables when applicable**. If you need to use them in conditional expressions, as required inputs to another action, or for other deterministic workflows. ## Related Topics - Reference: [Variables](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-variables.md) - Reference: [Conditional Expressions](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-expressions.md) - Reference: [Actions](https://developer.salesforce.com/docs/ai/agentforce/reference/ascript-ref-actions.md) - _Trailhead_: [Agent Script Basics: Manage State Across a Multi-Turn Conversation](https://trailhead.salesforce.com/content/learn/modules/agent-script-basics) # Agent Script Reference Use this reference to look up Agent Script syntax, keywords, and concepts. For common patterns and examples, see [Agent Script Patterns](https://developer.salesforce.com/docs/ai/agentforce/patterns/ascript-patterns.md). **note:** Beginning in April 2026, agent **topics** are now called **subagents**. There are no changes to functionality. During this transition, you may see a mix of the new and previous terms in our documentation ## Syntax This table lists some of the key terms used in an Agent Script file. | Symbol | Description | More Info | | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | | `#` | Single-line comment. For example: `# This is a comment` | [Comments](https://developer.salesforce.com/docs/ai/agentforce/ascript-lang.md#comments-to-help-the-humans) | | `...` | Slot-fill token that instructs the LLM to set the value. For example: `with order_id = ...` | [Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-variables.md), [Utils](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-utils.md) | | `->` | Begins logic instructions. For example: `instructions: -> if @variables.verified:` | [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-instructions.md) | | `\|` | Begins prompt instructions. For example: `\| Help the customer with their order.` | [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-instructions.md) | | `{!expression}` | Resolve a variable or resource in prompt instructions. For example: `{!@variables.promotion_product}` | [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-instructions.md) | | `==`, `!=`, `<`, `>`, `is None`, etc. | Comparison operators. For example: `@variables.count > 0` | [Supported Operators](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-operators.md) | | `@actions.name` | Reference an action. For example: `run @actions.get_order` | [Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-actions.md) | | `@outputs.name` | Reference an action's output value. For example: `set @variables.status = @outputs.status` | [Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-actions.md) | | `@subagent.name` | Delegate to another subagent. For example: `consult: @subagent.specialist` | [Tools](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-tools.md#referencing-a-subagent-as-a-tool) | | `@utils.escalate` | Define a tool that escalates to a human service rep. For example: `escalate: @utils.escalate` | [Utils](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-utils.md#utilsescalate) | | `@utils.setVariables` | Define a tool that instructs the LLM to set variable values. For example: `set_name: @utils.setVariables` | [Utils](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-utils.md#utilssetvariables) | | `@utils.transition to` | Define a tool that transitions to a different subagent. For example: `@utils.transition to @subagent.Order_Management` | [Utils](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-utils.md#utilstransition-to) | | `@variables.name` | Reference a variable from logic instructions. For example: `@variables.order_id` | [Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-variables.md) | | `actions` | Define agent actions or tools available from a subagent. | [Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-actions.md), [Tools](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-tools.md) | | `after_reasoning` | Run logic after the reasoning loop exits. | [After Reasoning](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-before-after-reasoning.md) | | `available when` | Conditionally show or hide a tool. For example: `available when @variables.verified == True` | [Tools](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-tools.md) | | `config` | Top-level block for agent configuration. | [Config Block](https://developer.salesforce.com/docs/ai/agentforce/ascript-blocks.md#config-block) | | `connection` | Top-level block for external connections like Enhanced Chat. For example: `connection messaging:` | [Connection Block](https://developer.salesforce.com/docs/ai/agentforce/ascript-blocks.md#connection-block) | | `if` / `else` | Conditional branching. For example: `if @variables.is_member == True:` | [Conditional Expressions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-expressions.md) | | `instructions` | Guidance for the LLM within system or reasoning blocks. | [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-instructions.md) | | `language` | Top-level block for supported languages. | [Language Block](https://developer.salesforce.com/docs/ai/agentforce/ascript-blocks.md#language-block) | | `linked` | Declare a variable whose value comes from an external source. For example: `session_id: linked string` | [Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-variables.md#linked-variables) | | `messages` | System messages like welcome and error prompts. | [System Block](https://developer.salesforce.com/docs/ai/agentforce/ascript-blocks.md#system-block) | | `modality voice` | Top-level block that defines how an Agentforce Voice agent speaks, including the voice persona and voice model. | [Configure Voice Models](https://developer.salesforce.com/docs/ai/agentforce/ascript-voice.md) | | `mutable` | Allow a variable's value to be changed. For example: `order_id: mutable string = ""` | [Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-variables.md#custom-variables) | | `reasoning` | Block containing instructions and tools for the LLM. | [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-instructions.md) | | `reasoning.actions` | Tools the LLM can choose to call within a subagent. | [Tools (Reasoning Actions)](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-tools.md) | | `reasoning.instructions` | Prompt and logic instructions sent to the reasoning engine. | [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-instructions.md) | | `run` | Execute an action deterministically. For example: `run @actions.get_order` | [Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-actions.md#call-an-action-in-the-reasoning-logic) | | `set` | Store a value in a variable. For example: `set @variables.status = @outputs.status` | [Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-variables.md), [Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-actions.md) | | `start_agent` | Entry point block for subagent classification and routing. For example: `start_agent agent_router:` | [Start Agent Block](https://developer.salesforce.com/docs/ai/agentforce/ascript-blocks.md#start-agent-block) | | `system` | Top-level block for agent instructions and messages. | [System Block](https://developer.salesforce.com/docs/ai/agentforce/ascript-blocks.md#system-block) | | `system.instructions` | Override system instructions for a specific subagent. | [System Overrides](https://developer.salesforce.com/docs/ai/agentforce/patterns/ascript-patterns-system-overrides.md) | | `target` | The flow or action target for an agent action. For example: `target: "flow://Get_Order"` | [Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-actions.md) | | `subagent` | Top-level block defining a subagent's instructions and actions. For example: `subagent Order_Management:` | [Subagent Blocks](https://developer.salesforce.com/docs/ai/agentforce/ascript-blocks.md#subagent-blocks) | | `topic` | Deprecated. Use `subagent` instead. | [Subagent Blocks](https://developer.salesforce.com/docs/ai/agentforce/ascript-blocks.md#subagent-blocks) | | `transition to` | Move to a different subagent from logic instructions. For example: `transition to @subagent.wrap_up` | [Utils](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-utils.md#utilstransition-to) | | `variables` | Top-level block for global agent variables. | [Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-variables.md) | | `with` | Bind an input parameter. For example: `with order_id = @variables.order_id` | [Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-actions.md) | ## Concepts These reference topics cover key concepts and terms associated with Agent Script. - **[Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-actions.md)** - Define executable tasks that an agent can perform, such as running a flow or transitioning to a new subagent. - **[After Reasoning](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-before-after-reasoning.md)** - Optional block inside a subagent that runs after the reasoning loop exits. - **[Blocks](https://developer.salesforce.com/docs/ai/agentforce/ascript-blocks.md)** - The structural components of an Agent Script, where each block contains a set of properties that describe data or procedures. - **[Conditional Expressions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-expressions.md)** - Deterministically specify what actions to take or which prompts to include based on the current context. - **[Configure Voice Models](https://developer.salesforce.com/docs/ai/agentforce/ascript-voice.md)** - Select and configure the text-to-speech voice model for an Agentforce Voice agent using the `modality voice` block. - **[Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-instructions.md)** - Instructions that Agentforce resolves into a prompt for the LLM. - **[Start Agent Block](https://developer.salesforce.com/docs/ai/agentforce/ascript-blocks.md#start-agent-block)** - A special subagent used for subagent classification, filtering, and routing. - **[Supported Operators](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-operators.md)** - The comparison, logical, and arithmetic operators you can use in Agent Script. - **[Tools (Reasoning Actions)](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-tools.md)** - Executable functions that the LLM can choose to call, based on the tool's description and current context. - **[Subagents](https://developer.salesforce.com/docs/ai/agentforce/ascript-blocks.md#subagent-blocks)** - A set of instructions, actions, and reasoning that defines a job that an agent can do. - **[Utils](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-utils.md)** - Utility functions used as tools, such as transitioning to subagents or setting variable values. - **[Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-variables.md)** - Let agents track information across conversation turns. # Agent Script Reference: Actions An action defines a task that a subagent can perform, such as calling a Flow, a prompt template, or an Apex class. You can store the action's output in a variable, make the output available to the reasoning engine, and choose whether the LLM can display the output to customers. A subagent can have many actions. You can import an action from a library or define it directly in the subagent. Subagents don't share actions - each action is unique to a subagent. If you import an action to a subagent, the subagent gets its own copy of the imported action. You define a subagent's actions in the `actions` block. #### Deterministically Call an Action You can call the action explicitly from the logic section of a subagent's `reasoning` block. In this case, the action is run every time the subagent is run, as the agent parses the subagent. You can also call the action from the subagent's `after_reasoning` block. In this case, the action is run after the subagent exits, every time the subagent is run. #### Allow the LLM to Subjectively Use an Action You can _also_ expose the defined action to the LLM in the subagent's `reasoning.actions` block, which is where [tools](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-tools.md) are specified. In this case, Agentforce passes the tool with your specified inputs to the LLM after parsing the entire subagent. The LLM can subjectively choose to run the tool based on the current context. _If_ the tool is run, it's run when the LLM receives the resolved prompt, not when the agent parses the subagent. To provide more explicit instructions to the LLM, you can optionally reference the tool from the prompt. In this example, we explicitly reference the `send_verification_code_tool` tool: ```agentscript | Ask the user for the verification code they received and verify it using {!@actions.send_verification_code_tool}. ``` #### Chain an Action When you expose a defined action to the LLM in the reasoning actions block, you can specify another action to run immediately afterwards. In this example, the `ScheduleOrder` action is run immediately after the `GetOrderByNumber` action. ```agentscript reasoning: instructions: -> | You are a helpful agent. actions: # get the order's details GetOrderByOrderNumber: @actions.GetOrderByOrderNumber with contactRecord = ... with orderNumber = ... set @variables.orderDetails = @outputs.orderDetails # automatically run the ScheduleOrder action after you get the order's details run @actions.ScheduleOrder with orderDetails = @variables.orderDetails set @variables.DeliveryDate = @outputs.deliveryDate ``` ## Example - Defining and Using Actions and Tools In this example, we define a single action, `send_verification_code_action`. We explicitly call the action from the logic section of the reasoning instructions. We also expose the action as a tool to the LLM (`send_verification_code_tool`), so that the LLM can choose to call the action if the customer didn't get the verification code the first time. ```agentscript subagent my_topic: # Agentforce actions go in the subagent actions block actions: send_verification_code_action: description: "Send a verification code to the member and verify confirmation." inputs: email: string member_number: string outputs: verification_code: string member_name: string target: "flow://Get_Verification_Code" reasoning: # LLM tools (aka reasoning actions) go in the reasoning actions block # which can include pointers to Agentforce actions. These tools are sent to the LLM to be used # at the LLM's discretion. actions: send_verification_code_tool: @actions.send_verification_code_action with email=@variables.member_email with member_number=@variables.member_number set @variables.verification_code=@outputs.verification_code instructions: -> # We explicitly call a subagent action from # the logic section of the reasoning instructions # In this case, the customer is sent a verification code # each time the subagent is run, as the agent is parsing the subagent. if @variables.member_email != "": run @actions.send_verification_code_action with email=@variables.member_email with member_number = @variables.member_number set @variables.verification_code=@outputs.verification_code set @variables.member_name=@outputs.member_name # In this case, we call our tool (a reasoning action) from # the prompt section of the reasoning instructions. # Calling the tool from the prompt isn't required, because # the LLM can usually figure out which tool to use. | Ask the user for the verification code they received and verify it using {!@actions.send_verification_code_tool}. ``` So you can call actions (specified in subagent.actions) deterministically, and you can expose actions as tools (specified in subagent.reasoning.actions) that the LLM can choose to use based on the current context. **note:** In the Actions and Tools example, the action is defined as `send_verification_code_action` and exposed as a tool called `send_verification_code_tool`. If you create actions in the UI and expose them as tools, the action and the tool have the same name. See [Using Actions](#using-actions), [Tools (Reasoning Actions)](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-tools.md), and [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-instructions.md). ## Action Properties An action definition contains these properties. | Property | Description | | :---------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [action name](#action-name) | Required string. The action's name. | | description | Optional string. Description of the action's behavior and purpose. If not provided, Agentforce creates a description from the action's name. Use `\|` for multiline descriptions. Your action descriptions should be meaningful - the LLM reads the description when deciding whether to call the action. | | [inputs](#inputs) | Optional object. Defines the action's input parameters, if any. If the reference action has a required input parameter that isn't specified, the LLM tries to provide the input using [slot-filling](https://developer.salesforce.com/docs/ai/agentforce/patterns/ascript-patterns-variables.md#let-the-llm-set-variables-with-user-entered-information-slot-filling)). **Note:** Agentforce only tries to slot-fill inputs that are _required_ and _unbound_. | | include_in_progress_indicator | Optional boolean (`True`/`False`). Indicates whether the agent shows progress indicator when running the action. | | [target](#target) | Required string. Reference to an executable (apex, flow, or prompt). | | label | Optional string. The action's name to display to the customer. Auto-generated if not specified. By default, Agentforce creates the label from the action's name, where `my_action` becomes "My Action". | | [outputs](#outputs) | Optional object. Defines the action's output parameters, if any. | | require_user_confirmation | Optional boolean. Indicates whether the customer must confirm before the agent runs the action. | ### action name The action's identifier, which you use to run the action. Action names must follow Salesforce developer name standards: - Begin with a letter, not an underscore. - Contain only alphanumeric characters and underscores. - Can't end with underscore. - Can't contain consecutive underscores (\_\_). - Maximum length of 80 characters. - `snake_case` is recommended. ### inputs Defines the action's input parameters, their [type](#parameter-types), and whether the input is required. For example: ```agentscript inputs: email: string label: "Email Address" description: "Customer's email address" is_required: True ``` #### Parameter Types You can use these types for input and output parameters: - `string` - text values - `number` - numeric values (floating point) - `integer` - integer values - `long` - long integer values - `boolean` - True/False values - `object` - complex objects - `date` - date values (YYYY-MM-DD) - `datetime` - dateTime values - `time` - time values - `currency` - currency values - `id` - Deprecated. Use `string` for Salesforce IDs. - list[``] - a list of values of the same type. You can use any supported type in this list. For example, `list[string]` or `list[number]`. ### target A reference to an executable. Use the format `{TARGET_TYPE}://{DEVELOPER_NAME}`. An action can have these targets: - `apex` (Apex) - `flow` (Flow) - `prompt` (Prompt Template) For example: ```agentscript flow://AssignSalesRep ``` ```agentscript prompt://check_bookings ``` ### outputs Defines the action's output parameters and the parameters' properties. By default, the agent remembers the action's output information for the entire session. The agent can make choices based on the information, and use the information to answer customer questions. For example, if a `get_product_care` action returns information about how to maintain a product, the agent remembers that information for the entire session, and can use the information to answer questions. Output parameters can be of [these types](#parameter-types). **important:** To hide output information from the agent, set the output parameter's `filter_from_agent` property to `True`. Supported properties for output parameters are: | Property | Description | | :----------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `description` | Optional. String. Description of the output parameter. By default, Agentforce generates this property from the parameter name. For example, the parameter `error_code` becomes `Error Code`. | | `developer_name` | Required. String. Value that can override the parameter's developer name. | | `label` | Optional. String. Human-readable label for the output parameter's value. By default, Agentforce autogenerates the label from the output parameter's name. For example, `error_code` becomes `Error Code`. | | `complex_data_type_name` | Required if the parameter is a complex data type. String. Indicates the type returned by the target. For example, suppose that an action has a flow target and an output parameter called `customer_info`. If the flow returns information of type `lightning__recordInfoType`, the action's `customer_info` parameter must have the type `object` and the property `complex_data_type_name: lightning__recordInfoType`. **Note:** These complex types can also be [custom Lightning types](https://developer.salesforce.com/docs/ai/lightning-types/lightning-types.md). | | `filter_from_agent` | Optional. Boolean. If `True`, the output is excluded from the agent's context. If `False`, the output is included in the agent's context. Default value is `False`. | For example: ```agentscript outputs: customer_found: boolean label: "Customer Found" filter_from_agent: True ``` ## Using Actions Once you've defined an action in the subagent's `reasoning.actions` block, you can call the action in a subagent's reasoning logic, or expose it as a tool to the LLM. ### Call an Action in the Reasoning Logic To ensure that an action runs every time a subagent runs, use `run @actions.` in the subagent's `reasoning` block. In this example, an action checks business hours. The action doesn't require input, and we store the action's output in variables. These variables can be accessed by other subagents, or by this subagent next time it runs. ```agentscript reasoning: instructions: -> run @actions.check_business_hours set @variables.is_business_hours=@outputs.is_business_hours set @variables.next_open_time=@outputs.next_open_time ``` ### Expose the Action as a Tool for the LLM You can expose an action as a tool in the reasoning actions block, enabling the LLM to choose whether to run the tool. When you expose the tool to the LLM, you can choose whether to explicitly reference the tool from any prompts you specify in the reasoning block. See [Tools (Reasoning Actions)](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-tools.md). ```agentscript reasoning: actions: load_order_details: @actions.Get_Order_Details with order_number=@variables.order_number with customer_id=@variables.customer_id ``` Typically, an LLM recognizes when to use a tool. However, you can also use `{!@actions.}` in the prompt to provide more context. ```agentscript reasoning: instructions: -> | If not within business hours, create a support case by using {!@actions.create_case}. Share the Case Number and when to expect follow-up ({!@variables.next_open_time}). ``` ## Related Topics - [Flow of Control](https://developer.salesforce.com/docs/ai/agentforce/ascript-flow.md) - [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-instructions.md) - [Tools (Reasoning Actions)](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-tools.md) # Agent Script Reference: After Reasoning Agentforce runs a subagent's `after_reasoning` block after the reasoning loop exits, on every request. The `after_reasoning` block can contain logic, actions, transitions, or other directives, but can't contain the `|` (pipe) command. Typical use cases are to set customer-entered information into a variable, transition to a different subagent, or run an action. **note:** You can't use `before_reasoning` or `after_reasoning` in a subagent that uses the EinsteinHyperClassifier model. For example, this `after_reasoning` block sets the appointment duration based on the urgency level. ```agentscript after_reasoning:-> if @variables.urgency_level == "urgent": set @variables.estimated_duration = 15 if @variables.urgency_level == "routine": set @variables.estimated_duration = 30 ``` To see how Agentforce creates an LLM prompt from a subagent that contains an `after_reasoning` block, see [Example: How Agentforce Creates a Prompt from a Subagent](https://developer.salesforce.com/docs/ai/agentforce/ascript-flow.md#example-how-agentforce-creates-a-prompt-from-a-subagent). **note:** Agentscript also supports a `before_reasoning` block with the same capability and syntax as the `after_reasoning` block. The `before_reasoning` block is functionally equivalent to adding logic to the beginning of a subagent's instructions. ## Transitions in after_reasoning If a subagent [transitions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-utils.md#utilstransition-to) to a new subagent partway through execution, the original subagent's `after_reasoning` block isn't run. When calling [transitions](https://developer.salesforce.com/docs/ai/agentforce/ascript-flow.md#transitioning-between-subagents) in after reasoning, use `transition to` rather than `@utils.transition to`. For example: ```agentscript after_reasoning: if @variables.case_type != "": transition to @subagent.case_creation ``` ## Related Topics - [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-instructions.md) # Agent Script Reference: Conditional Expressions `if`, `else if`, and `else` conditions deterministically specify what actions to take or which prompts to include. To specify complex conditions, use parentheses `()` to group `and` and `or` operators within a condition. For example, you can check a variable's value and then run an action based on the result: ```agentscript # If the tracking number (represented as a string) isn't empty and is not None, get the tracking updates if @variables.tracking_number is not None and @variables.tracking_number != "": run @actions.Get_Tracking_Updates else: run @actions.Ask_Tracking_Number ``` If you need to nest `and` and `or`operators, you can use parentheses `()`. In this example, the grouped condition `(@variables.HasSalesInterest == True or @variables.WantsMeeting == True)` is evaluated first. The condition evaluates as true if either one of `HasSalesInterest` or `WantsMeeting` is true. ```agentscript reasoning: instructions: -> | Select the best tool to call based on conversation history and user's intent. actions: go_to_Qualify: @utils.transition to @subagent.Qualify available when @variables.customerType == "Valued" and @variables.QualificationEnabled == True and (@variables.HasSalesInterest == True or @variables.WantsMeeting == True) and @variables.QualificationFlowStep != "COMPLETE" ``` You can also check a variable in order to set other variables. ```agentscript if @variables.order_number == "" and @variables.customer_email == "": set @variables.order_found = False set @variables.customer_verified = False ``` You can use a conditional expression to determine which natural-language prompt to include. ```agentscript if @variables.is_late == True: | Apologize to the customer for the delay in receiving their order. else: | Tell the customer their order is arriving as scheduled. ``` You can use `if` and `else` inside reasoning instructions to conditionally include different prompt lines for the LLM. ```agentscript reasoning: instructions: -> | Your job is solely to help with issues and answer questions by searching knowledge articles. if @variables.support_tier == "premium": | This is a premium customer. Prioritize their request and offer proactive suggestions. else: | This is a standard customer. Answer their questions helpfully and suggest upgrading for faster support. | If the customer's question is too vague, ask for more details. ``` Use `else if` to specify mutually exclusive conditions. ```agentscript subagent ReportCurrentState: description: | Route to this subagent if the user wants to know the current state reasoning: instructions: -> if @variables.state == "A": | Tell the user we're in state A. else if @variables.state == "B": | Tell the user we're in state B. else if @variables.state == "B": | Tell the user we're in state C. else: | Chat about the state of a local sports team. ``` You can check whether a variable has a value. ```agentscript # Note this example demonstrates correct syntax, NOT how to design a production agent reasoning: instructions: -> if @variables.account_id is None: | What's the account ID for this order? if @variables.is_premium_user is not None: | This customer's premium status is set to {!@variables.is_premium_user}. if @variables.order_lines != None: | Order lines on this order: {!@variables.order_lines}. if @variables.scheduled_date is None: | When would you like to schedule this appointment? ``` **Related Topics** - [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-instructions.md) - [Supported Operators](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-operators.md) - _Trailhead_: [Programmatic Instructions in Agentforce: Use Conditional Logic to Send the Right Prompt for Each Context](https://trailhead.salesforce.com/content/learn/modules/programmatic-instructions-in-agentforce) # Agent Script Reference: List Variables A [custom](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-variables.md) variable can be a list of values. A list can hold any supported variable type, such as strings, booleans, numbers, or objects. ## Creating a List Variable When you create a list in the `variables` block, specify the variable type in brackets. You can leave the list uninitialized, initialize an empty list, or set default values. ```agentscript variables: # Declare a list of objects all_accounts: mutable list[object] description: "The list of account objects returned by the action" label: "all_accounts" # Declare a list of strings with default values CompetencyQuestions: mutable list[string] = ["Tell me about a time you disagreed with a coworker.", "Tell me about one of your favorite shifts.", "What are the most important qualities in a candidate?"] description: "List of questions to determine competency." ``` ## Reference an Item in a List To reference an item in a list, use `json_path` or bracket `[]` syntax. Lists are zero-indexed, so to get the first item in your list, use `[0]`. To reference a field in a list of objects, use `data.`. Note that `json_path` syntax returns the value enclosed in `[""]` characters, while bracket syntax returns the raw value. | Syntax | Example | Example Return Value | | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | -------------------- | | `@variables.[].data.` | The name of the fourth account in a list of accounts:
`@variables.all_accounts[3].data.Name` | `Acme Corp` | | `json_path(@variables., "$[].data.")` | The name of the fourth account in a list of accounts:
`json_path(@variables.all_accounts, "$[3].data.Name")` | `["Acme Corp"]` | ### Example: Reference a List of Strings in Reasoning Instructions This example shows how to use bracket syntax to get the third item in a list of strings. ```agentscript # Ask the user the 3rd question in the list of questions reasoning: instructions: -> | Ask the user this question: {!@variables.CompetencyQuestions[2]} ``` ### Example: Reference a List of Objects in After Reasoning This example shows: - How to use `json_path` syntax to get the value of the Name field from the third account in a list of Account objects. - How to use bracket syntax to get the value of the Name field from the fourth account in a list of Account objects. ```agentscript # From a list of accounts, store the third and fourth account name in a variable after_reasoning: # stores Name field enclosed in [""], for example ["Pyramid Construction Inc."] set @variables.third_account_name = json_path(@variables.all_accounts, "$[2].data.Name") # stores Name field without added characters, for example Dickenson Inc set @variables.fourth_account_name = @variables.all_accounts[3].data.Name ``` ## Supported Operations on List Variables You can use these operations on your list variables. | Operation | Syntax | | :---------------------------------------------------------- | :------------------------------------------ | | Get the length of a list | `len(@variables.myList)` | | Return the maximum of a list of numbers | `max(@variables.scores)` | | Return the minimum of a list of numbers | `min(@variables.scores)` | | Serialize a variable to a JSON string | `to_json(@variables.myList)` | | Use JSONPath syntax to reference a specific value in a list | `json_path(@variables.myList, "$[*].name")` | ## Related Topics - Pattern: [Using Variables Effectively](https://developer.salesforce.com/docs/ai/agentforce/patterns/ascript-patterns-variables.md) - Pattern: [Using List Variables](https://developer.salesforce.com/docs/ai/agentforce/patterns/ascript-patterns-var-list.md) - Reference: [System Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-variables-system.md) - Reference: [Custom Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-variables.md) - [Flow of Control](https://developer.salesforce.com/docs/ai/agentforce/ascript-flow.md) - Reference: [Utils](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-utils.md) # Agent Script Reference: Reasoning Instructions A subagent's reasoning block contains instructions that Agentforce resolves into a prompt for the LLM. The resolved prompt instructs the LLM to perform the subagent's purpose. See [Processing a Subagent](https://developer.salesforce.com/docs/ai/agentforce/ascript-flow.md#processing-a-subagent). **note:** In general, shorter reasoning instructions result in more accurate and reliable results. In the example, the logic deterministically sends a verification code when an email address is present and saves returned values in variables. The prompt guides the user to provide and validate the code, with instructions to confirm the email and resend if needed. ```agentscript reasoning: instructions: -> if @variables.member_email != "": run @actions.send_verification_code with email=@variables.member_email with member_number = @variables.member_number set @variables.verification_code=@outputs.verification_code set @variables.member_name=@outputs.member_name | Greet the user and inform them that to help them get started you've sent them a verification code via email. Ask the user for the verification code they received and verify it using {!@actions.validate_verification_code}. If the user says they did not receive the code, ask them to confirm their email and resend the verification code using {!@actions.send_verification_code} ``` To use variables in reasoning instructions, use `{!@variables.}`. The prompt is resolved with the variable's value. There are two different parts of reasoning instructions: logic instructions and prompt instructions. Logic instructions are deterministic or [conditional expressions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-expressions.md) that determine certain requirements, run actions, and set variables. Prompt instructions are passed as natural language to the LLM if the conditions are met. The prompt instructions can still reference literal values through `@variables`, `@utils`, and `@actions`. The `|` (pipe) command for multiline strings can also be used for indented multiline prompt instructions before or after the deterministic logic instructions are followed. ```agentscript reasoning: instructions: -> # LOGIC INSTRUCTIONS if @variables.ready_to_book: run @actions.get_account_info with account_id=@variables.account_id set @variables.hotel_code=@outputs.hotel_code run @actions.get_hotel_info with hotel_code=@variables.hotel_code set @variables.hotel_info = @outputs.hotel_info # PROMPT INSTRUCTIONS | You are a helpful assistant that can answer questions about a hotel. Here's the latest hotel information {!@variables.hotel_info}. If the user asks about availability, please use the action: {!@actions.get_availability} action that they give you the date range they are traveling on. If they indicate they wish to book, please transition over to a booking agent by calling the action {!@actions.transition_to_booking} action. If they indicate that they wish to ask about another hotel, use the {!@actions.lookup_hotel} action and tell them they'll be able to ask about that hotel. ``` **Related Topics** - [Flow of Control](https://developer.salesforce.com/docs/ai/agentforce/ascript-flow.md) - [Tools (Reasoning Actions)](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-tools.md) - [Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-variables.md) - [Conditional Expressions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-expressions.md) # Agent Script Reference: Supported Operators In Agent Script, you can use these operators. | Category | Operator | Description | Example | | :--------- | :------- | :--------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------- | | Comparison | `==` | Equal to | `@variables.count == 10` | | | `!=` | Not equal to | `@variables.status != "done"` | | | `<` | Less than | `@variables.age < 18` | | | `<=` | Less than or equal | `@variables.score <= 100` | | | `>` | Greater than | `@variables.count > 0` | | | `>=` | Greater than or equal | `@variables.total >= 50` | | | `is` | Identity check | `@variables.value is None` | | | `is not` | Negated identity check | `@variables.data is not None` | | Logical | `and` | Logical AND | `@variables.a and @variables.b` | | | `or` | Logical OR | `@variables.x or @variables.y` | | | `not` | Logical NOT | `not @variables.flag` | | Arithmetic | `+` | Addition | `@variables.count + 1` | | | `-` | Subtraction | `@variables.total - 5` | | Grouping | `( )` | Parentheses | `(@variables.x or @variables.y) and @variables.z` See [Agent Script Reference: Conditional Expressions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-expressions.md) for examples. | **Related Topics** - [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-instructions.md) - [Conditional Expressions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-expressions.md) # Agent Script Reference: System Variables Agent Script provides predefined, prepopulated system variables that you can use in your agent. To access system variables, use `@system_variables.`. A system variable is: - read-only, so you can't change its value - predefined, so you don't define it in the `variables` block - used in the same places as a custom variable or a linked variable For custom and linked variable definitions, see [Agent Script Reference: Variables (Custom and Linked)](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-variables.md). ## `user_input` The `user_input` system variable contains the customer's most recent utterance (**not** the entire conversation history). **note:** The LLM remembers the entire conversation history, so you don't typically need to use `@system_variables.user_input` unless you're passing the last thing a customer said into an action. ### Example - Analyze Customer Sentiment In this example, we pass the last customer utterance into a sentiment analysis action. Although the agent's LLM can also analyze sentiment, we want to use a prompt template action that understands industry-specific terminology and our customer's rapidly changing language patterns. ```agentscript reasoning: actions: AnalyzeSentiment: @actions.AnalyzeSentiment with utterance = @system_variables.user_input set @variables.customer_sentiment = @outputs.sentiment_classification ``` ## `current_modality` The `current_modality` system variable indicates whether the agent is currently operating in voice or text mode. This variable is automatically populated on every inbound turn, based on the connection channel: | Connection Type | `current_modality` value | | -------------------------- | ------------------------ | | Telephony | `"voice"` | | Messaging/Enhanced Chat v2 | `"text"` | If your agent isn't bound to a telephony or messaging/ECv2 connection, the `current_modality` system variable isn't set (value is `None`). Use this system variable when you want the agent to behave differently in different modes. For example, your agent can keep responses short and free of formatting on voice mode, but provide richer formatting responses during text mode. ### Example - Adapt Response to Modality In this example, we pass the current modality into an action so it can tailor its output: ```agentscript reasoning: actions: FormatResponse: @actions.FormatResponse with modality = @system_variables.current_modality ``` ## `current_connection` The `current_connection` system variable identifies the connected client for the current turn. This variable is automatically populated on every inbound turn. **note:** This value may be unpopulated (None) until the runtime finishes configuring the connection. ### Example - Pass Connection Context to an Action ```agentscript reasoning: actions: LogInteraction: @actions.LogInteraction with connection = @system_variables.current_connection ``` ## `uploaded_files` The `uploaded_files` system variable is a list of `File` objects representing files that the customer uploaded. The agent stores the 10 most recently uploaded files for the duration of the session. If the customer hasn't uploaded any files, then `uploaded_files` is empty. Each `File` has these fields: `id`, `file_url`, `name`, and `mime_type`. ```agentscript # use slice operations to get the first 5 files @system_variables.uploaded_files[0:5] # Get the number of files uploaded len(@system_variables.uploaded_files) ``` To use `@system_variables.uploaded_files`, enable file uploads in the [`file_upload`](https://developer.salesforce.com/docs/ai/agentforce/ascript-blocks.md#file-upload-sub-block) block of your agent's config. ## Related Topics - Reference: [Variables (Custom and Linked)](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-variables.md) # Agent Script Reference: Tools (Reasoning Actions) Tools are executable functions that the LLM can choose to call, based on the tool's description and the current context. You define tools in the subagent's `reasoning.actions` block. Tools can be [actions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-actions.md) or other [utilities](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-utils.md). Tools must wrap an action or a `@utils` function. Use `with` to bind parameters and `set` to assign output values to variables. You can use the `available when` parameter to deterministically specify when the tool is available. **tip:** **Tools vs. Actions**. Agent Script has two `actions` blocks: - **Subagent actions** (`subagent.actions`) — Available to you from logic-based reasoning instructions - **Reasoning actions** (`subagent.reasoning.actions`) — Available to the LLM to call as needed, and can be referenced in your prompt-based instructions Since reasoning actions can reference subagents and utilities in addition to regular subagent actions, we sometimes call them "tools" to reflect their broader uses. In Canvas view, this distinction is handled automatically, but it's important to understand when writing Agent Script directly. ### How the LLM Decides Which Tool to Call The LLM looks at the names and descriptions of all the tools when deciding whether to call a tool. Tools should have meaningful names and descriptions. To provide more context, you can explicitly reference a tool in the reasoning instructions. For example, these reasoning instructions don't provide additional context about which tool to call. ```agentscript reasoning: instructions: -> | Use the action that best matches the user's message and the conversation context. actions: # This tool calls the Get_Customer_Info action lookup_customer: @actions.Get_Customer_Info with email=@variables.customer_email set @variables.customer_desc = @outputs.customer_description # This tool writes the customer-provided information # into the specified variables. The LLM can choose when to use it. capture_order_info: @utils.setVariables description: "Capture order search information from customer" with order_number=@variables.order_number with customer_email=@variables.customer_email available when @variables.customer_verified == True # This tool transitions to a subagent that # displays detailed information about the order show_order_details: @utils.transition to @subagent.order_details description: "Show detailed order information" ``` These reasoning instructions provide more details about when to use the `capture_order_info` tool. ```agentscript reasoning: instructions: -> | If the customer is verified and provides their order number or email, use {!@actions.capture_order_info} to store the information. Otherwise, use the action that best matches the user's message and the conversation context. actions: # This tool calls the Get_Customer_Info action lookup_customer: @actions.Get_Customer_Info with email=@variables.customer_email set @variables.customer_desc = @outputs.customer_description # This tool writes the customer-provided information # into the specified variables. The LLM can choose when to use it. capture_order_info: @utils.setVariables description: "Capture order search information from customer" with order_number=@variables.order_number with customer_email=@variables.customer_email available when @variables.customer_verified == True # This tool transitions to a subagent that # displays detailed information about the order show_order_details: @utils.transition to @subagent.order_details description: "Show detailed order information" ``` ### Defining When a Tool Is Available Use `available when` to define the conditions that must exist for the LLM to use the tool. The clause after `available when` must be a valid [conditional expression](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-expressions.md) built from [supported operators](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-operators.md). ```agentscript reasoning: actions: cancel_booking: @actions.cancel_booking with booking_id=@variables.current_booking_id available when @variables.booking_status == "active" admin_override: @actions.admin_override available when @variables.user_role == "admin" go_to_identity: @utils.transition to @subagent.Identity description: "verifies user identity" available when @variables.verified == False ``` ## Referencing a Subagent as a Tool In reasoning actions, you can reference a subagent directly with `@subagent.` or through a declarative transition ([`@utils.transition to`](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-utils.md#utilstransition-to)). Use a direct `@subagent.` reference to delegate to a subagent, similar to an action or tool call. After the referenced subagent is run, the flow returns to the original subagent. This behavior is different from a declarative transition (`@utils.transition to`) in that transitions are one way, whereas a direct subagent reference returns to the original caller. If a referenced subagent includes a declarative transition, the flow follows that path until it ends, and then returns to the original subagent. In this code sample, you can see both methods of calling another subagent. ```agentscript reasoning: actions: # Transitions to the other subagent and does not return show_order_details: @utils.transition to @subagent.order_details description: "Show detailed order information" # Runs the other subagent as a tool, synthesizes the result, then can run more tools consult_specialist: @subagent.specialist_topic description: "Consult specialist for complex questions" available when @variables.needs_expert_help == True ``` ## Related Topics - [Flow of Control](https://developer.salesforce.com/docs/ai/agentforce/ascript-flow.md) - [Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-actions.md) - [Utils](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-utils.md) - [Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-variables.md) # Agent Script Reference: Utils Utils are utility functions that can be used as tools, for example transition to subagents, run actions, or instruct the LLM to set variable values based on a customer's utterance. ## utils.transition to Tells the agent to move to a different subagent. For examples and patterns, see the [Transitions Pattern](https://developer.salesforce.com/docs/ai/agentforce/patterns/ascript-patterns-transitions.md). Transitions are one way. There's no return of control to the calling subagent. `transition to` executes immediately when encountered. The execution of the current directive block is halted, and control is passed to the new subagent. You can signal a hand off immediately after an action completes by including transition logic in the `actions:` block. However, this may not occur until all actions are run. ```agentscript # during reasoning reasoning: actions: go_to_identity: @utils.transition to @subagent.Identity description: "verifies user identity" available when @variables.verified == False go_to_order: @utils.transition to @subagent.Order_Management description: "Handles order lookup, refunds, order updates, and summarizes status, order date, current location, delivery address, items, and driver name." available when @variables.verified == True go_to_faq: @utils.transition to @subagent.General_FAQ description: "Handles FAQ lookup and provides answers to common questions." available when @variables.verified == True ``` This code sample provides multiple transitions for order management, user verification, and answering common questions. Because these particular transitions are specified from within the reasoning actions, they can be executed by the reasoning engine when applicable. See [Tools (Reasoning Actions)](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-tools.md). You can also transition to a subagent from your reasoning instructions using `transition to`. This sample transitions based on a variable state. ```agentscript if @variables.approval_required: transition to @subagent.approval_workflow ``` When the specified subagent has completed, the flow of control doesn't return to the original subagent, so you must explicitly create a transition back to the original subagent if that's what you want. When transitioning back to a subagent, the flow starts at the beginning of the subagent, not where it last left off. ```agentscript # in topic A, specify that the flow of control jumps to topic_b search_another: @utils.transition to @subagent.topic_b description: "Search for another order" # in topic B, specify that the flow of control goes (back) to topic_a back_to_order: @utils.transition to @subagent.topic_a description: "Return to order details" ``` See [Referencing a Subagent as a Tool](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-tools.md#referencing-a-subagent-as-a-tool). ## utils.setVariables Tells the agent to define a variable based on the natural language description. The `…` token instructs the LLM to set the value of the variable. The `description` instructs the LLM on how to set the value of the variable. ```agentscript reasoning: actions: set_first_name_variable: @utils.setVariables with first_name = ... description: "Get the user's first name" ``` ## utils.escalate Tells the agent to escalate to a human service rep. To use `utils.escalate`, you need an active Omni-Channel connection. This must be defined in a `connection messaging` block with `outbound_route_type` and `outbound_route_name` values. See [Agent Script Connection Block](https://developer.salesforce.com/docs/ai/agentforce/ascript-blocks.md#connection-block) and [Transfer Conversations from an Agent with an Omni-Channel Flow](https://help.salesforce.com/s/articleView?id=ai.service_agent_escalation.htm). The escalate utility function can be used instead of an escalation subagent. ```agentscript subagent my_topic_name: reasoning: instructions: | call the action {!@actions.escalate_to_human} if the user wants to speak with a human rep actions: escalate_to_human: @utils.escalate description: "Call this when you need to escalate to a human rep" available when @variables.in_business_hours ``` **note:** `escalate` is a reserved keyword and can't be used for subagent or action names. ## utils.end_session Tells the agent to end the conversation immediately. Use `utils.end_session` when the agent should terminate the session, for example after completing a task or when a specific condition is met. In this example, the LLM can choose to end the conversation, for example if the customer is making inappropriate utterances. ```agentscript reasoning: instructions: -> | Use your general knowledge to answer the user's questions. | If the user asks about aliens, you MUST say "aliens don't exist!" and run {!@actions.end_conversation} and end the conversation immediately. actions: end_conversation: @utils.end_session ``` In this example, the agent router chooses to run the `go_to_EndSession` action when the customer says the don't need any more help. The `go_to_EndSession` action transitions to the `EndSession` subagent, which runs the `end_session` util. ```agentscript variables: start_agent agent_router: label: "Agent Router" description: "Welcome the user and determine the appropriate subagent based on user input" model_config: model: "model://sfdc_ai__DefaultEinsteinHyperClassifier" reasoning: instructions: -> | Select the best tool to call based on conversation history and user's intent. actions: go_to_EndSession: @utils.transition to @subagent.EndSession description: "End the session when the user says the conversation is over, or they don't need any more help." subagent EndSession: label: "End Session" description: "End the session when the user says the conversation is over, or they don't need any more help." reasoning: instructions: -> | End the conversation immediately. actions: end_conversation: @utils.end_session description: "End the session when the user says the conversation is over, or they don't need any more help." ``` ## Related Topics - [Flow of Control](https://developer.salesforce.com/docs/ai/agentforce/ascript-flow.md) - Pattern: [Transitions](https://developer.salesforce.com/docs/ai/agentforce/patterns/ascript-patterns-transitions.md) - Reference: [Tools (Reasoning Actions)](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-tools.md) - Reference: [Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-variables.md) # Agent Script Reference: Variables (Custom and Linked) Variables let agents deterministically remember information across conversation turns, track progress, and maintain context throughout the session. You define all variables in the `variables` block, and all subagents in the agent can access the variables. This page covers custom and linked variables. For predefined runtime variables, see [Agent Script Reference: System Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-variables-system.md). - **[custom variable](#custom-variables):** You can initialize a variable with a default value, and the agent can change the variable's value. - **[linked variable](#linked-variables):** The value of a linked variable is tied to an output such as an action's output. Linked variables can't have a default value. ## Defining a Variable Define variables in the [`Variables`](https://developer.salesforce.com/docs/ai/agentforce/ascript-blocks.md#variables-block) block. ```agentscript CurrentState: mutable string = "gatheringInfo" description: "The current state, or step, of the interview." label: "State" visibility: "External" ``` ## Variable Names Variable names must follow Salesforce developer name standards: - Begin with a letter, not an underscore. - Contain only alphanumeric characters and underscores. - Can't end with underscore. - Can't contain consecutive underscores (\_\_). - Maximum length of 80 characters. ## Referencing Variables To reference a variable from the script, use `@variables.`. ```agentscript if @variables.Customer_Contact is None: set @variables.No_Matching_Contact = True ``` To reference a variable from within reasoning instructions, use `{!@variables.}`. ```agentscript reasoning: instructions: -> | Always use {!@variables.Customer_Email} for the customer's email address. ``` ## Custom Variables Custom variables have these properties: - `mutable` - Optional. Allows the agent to change the variable's value. To ensure a variable's value is never changed, define the variable without `mutable`. - `description` - describes the variable. Optional. If you want the LLM to use reasoning to set the variable's value, include a description to help the LLM set the value correctly. See [Let the LLM set variables with user-entered information (slot filling)](https://developer.salesforce.com/docs/ai/agentforce/patterns/ascript-patterns-variables.md#let-the-llm-set-variables-with-user-entered-information-slot-filling). - `label` - Optional. The variable's name as displayed in the UI. By default, the description is generated from the name. For example, if your variable's name is `my_var`, the UI displays the label `My Var`. - `visibility` - Optional. Default value is `Internal`. Set visibility to `External` to allow an API to set the variable's value, or to change the variable's value when [testing the agent in simulate mode](https://help.salesforce.com/s/articleView?id=ai.agent_test_in_builder.htm&language=en_US&type=5). ```agentscript variables: isPremiumUser: mutable boolean = False description: "Indicates whether the user is a premium user." label: "Has Gold Status" customer_loyalty_tier: mutable string = "standard" description:| Stores the customer's membership tier level. ``` Custom variables can have these types: | Type | Notes | Example | | :----------- | :----------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------- | | `string` | Any alphanumeric string without special characters. | `name: mutable string = ""` | | `number` | Use for both integers and decimals. For example, 42 or 3.14. Compiles to IEEE 754 double-precision floating point. | `age: mutable number`, `price: mutable number = 99.99` | | `boolean` | Allowed values are `True` or `False`. The value is case-sensitive, so capitalize the first letter. | `is_active: mutable boolean = True` | | `object` | Value is a complex JSON object in the form `{"key": "value"}.` | `order_line: mutable object = {"SKU": "abc12344409","count": 42}` | | `date` | Any valid date format. | `start_date: mutable date` | | `id` | Deprecated. Use `string` to store a Salesforce record ID. | See string type. | | `list[type]` | A list of values of the specified type. All primitive types and `object` type are supported. | `flags: mutable list[boolean] = [True, False, True]`, `scores: list[number] = [95, 87.5, 92]`, `obj_list: mutable list[object] = None` | ## No Value (None) and Empty String ("") Use `None` to check whether a variable has a value. You can use `None` with any variable type. For a string variable, you can also use `""` to check if the variable is set to an empty string. When checking string variables in conditional statements, you might want to use both `None` and `""`. For more information, see [Agent Script Reference: Conditional Expressions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-expressions.md). ## Linked Variables A linked variable's value is tied to a source, such as an action's output. Linked variables have these restrictions: - can't have a default value - can't be set by the agent - can't be an object or a list The `source` field references where the variable gets its value. Supported source namespaces are: | Namespace | Available Properties | Description | | :------------------ | :-------------------------------------------- | :----------------------------------- | | `@MessagingSession` | `Id`, `MessagingEndUserId`, `EndUserLanguage` | Properties of the messaging session | | `@MessagingEndUser` | `ContactId` | Properties of the messaging end user | | `@VoiceCall` | `Id` | Properties of the voice call | ```agentscript variables: session_id: linked string source: @MessagingSession.Id description: "The messaging session ID" contact_id: linked string source: @MessagingEndUser.ContactId description: "The contact ID of the end user" voice_call_id: linked string source: @VoiceCall.Id description: "The voice call ID" ``` Linked variables can have these types: - `string` - `number` - `boolean` - `date` - `id` (deprecated; use `string` for Salesforce record IDs) ## Examples and Patterns For examples and patterns using variables, see [Agent Script Pattern: Using Variables Effectively](https://developer.salesforce.com/docs/ai/agentforce/patterns/ascript-patterns-variables.md) and [Agent Script Pattern: Using List Variables](https://developer.salesforce.com/docs/ai/agentforce/patterns/ascript-patterns-var-list.md) ## Related Topics - Pattern: [Using Variables Effectively](https://developer.salesforce.com/docs/ai/agentforce/patterns/ascript-patterns-variables.md) - Pattern: [Using List Variables](https://developer.salesforce.com/docs/ai/agentforce/patterns/ascript-patterns-var-list.md) - Reference: [System Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-variables-system.md) - Reference: [List Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-variables-list.md) - [Flow of Control](https://developer.salesforce.com/docs/ai/agentforce/ascript-flow.md) - Reference: [Utils](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-utils.md) # Agent Service Reasoner Errors The Agent Service Reasoner manages agent conversations on two surfaces: the multi-agent orchestration layer, where connected subagents collaborate to complete complex tasks, and the single-agent reasoning endpoint, where individual agents process requests from users and calling applications. Errors from this service typically indicate that a request was malformed or missing required context, that the requested agent or session couldn't be found, that the caller lacked permission, or that a language model call timed out, was rate limited, or encountered a service-side failure. ## A2A_BAD_REQUEST A request to the multi-agent orchestration service was malformed or contained invalid parameters. The service received the request but rejected it because of an unsupported message type, invalid input variables, or a request structure it couldn't process. Retrying the same request won't help. The request itself needs to be corrected first. This error occurs when: - The request was missing required fields or used an unsupported message type. - The agent's input variables were invalid: wrong types, unknown variable names, or malformed values. - The request structure didn't match the format the service expects. ### How to Troubleshoot To resolve this error: 1. Check the detail field in the error response. It includes a specific reason for the rejection. 2. Validate the request against the connected subagent's configuration before resending. 3. If you constructed the request manually, compare it to a working example from the agent's published configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `A2A_BAD_REQUEST` - A redacted copy of the request ## A2A_CONFLICT Another task is already in progress for this conversation. The service rejected the new request to prevent concurrent tasks from corrupting the conversation's state. Wait for the active task to finish and try again. This error occurs when: - A follow-up message was sent before the previous task finished. - A retry of an earlier request arrived while the original task was still running. ### How to Troubleshoot To resolve this error: 1. Wait at least 5 seconds for the active task to complete, then try again. If your agent typically runs longer tasks, you may need to wait longer before trying again. 2. Send requests for a conversation one at a time. Don't start the next task until the previous one returns its final response. 3. If the conflict continues well beyond the expected task duration, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `A2A_CONFLICT` - The conversation context ID and the approximate time when the conflict occurred ## A2A_DESERIALIZATION_ERROR A request to the multi-agent orchestration service failed validation before it was processed. The request structure or data types didn't match the expected format. Retrying the same request won't help. The request needs to be corrected first. This error occurs when: - A field has the wrong data type, such as a number where text is expected. - A required field is missing from the request or the connected subagent's configuration. - The request contains malformed content, such as invalid characters or missing brackets. ### How to Troubleshoot To resolve this error: 1. Check the detail field in the error response. It identifies which field failed and why. 2. Compare your request to the connected subagent's published configuration to verify the expected format. 3. If you're constructing the request manually, validate it before sending. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `A2A_DESERIALIZATION_ERROR` - The full detail text from the error response (it identifies the failing field) - A redacted copy of the request ## A2A_NOT_FOUND The agent, session, or task referenced in the request couldn't be found. It may not exist, may have expired, or may not be accessible to the authenticated user. Retrying won't help. The identifier needs to be correct before the request can succeed. This error occurs when: - The agent ID doesn't match a registered agent. - The task or session ID has expired or was never created. - The request references a resource that belongs to a different org or user. ### How to Troubleshoot To resolve this error: 1. Verify the agent, task, or session ID is correct and hasn't expired. 2. If the resource was created earlier in a flow, confirm it hasn't been cleaned up. 3. Confirm you're authenticated as the user who owns the resource. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `A2A_NOT_FOUND` - The agent ID, task ID, or session ID the request was targeting ## A2A_PAYLOAD_TOO_LARGE The request to the multi-agent orchestration service exceeds the size limit. The service rejected it before processing. Reduce the size of the request before retrying. This error occurs when: - A field in the agent's input variables contains embedded file data that should be passed as a reference instead. - Input variables have accumulated data across multiple turns and the total has grown too large. - The full conversation history is being resent with each request instead of relying on the session state. ### How to Troubleshoot To resolve this error: 1. Identify which input variables are largest and reduce or remove them. 2. Replace embedded file data with references the agent can look up on demand. 3. Remove accumulated history the agent doesn't need to see again. 4. Resend the request with the reduced input. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `A2A_PAYLOAD_TOO_LARGE` - The approximate size of the request ## A2A_SECURITY_ERROR The authenticated user doesn't have permission to perform this action. The identity was confirmed, but the account lacks the required access to the agent or session being requested. Retrying won't help. The permissions need to change first. This error occurs when: - The user doesn't have the required permission set for the agent. - Your org's settings don't allow this type of access for this user. - The request is targeting an agent, task, or session that belongs to a different user or org. ### How to Troubleshoot To resolve this error: 1. Confirm the user's permissions include access to the agent they're trying to reach. 2. If acting on behalf of another user, verify that delegated access is in place. 3. If access should be allowed, contact your Salesforce admin to review the permissions. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `A2A_SECURITY_ERROR` - The agent ID or task ID the request was targeting ## A2A_SYSTEM This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `A2A_SYSTEM` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## A2A_TIMEOUT A request to the multi-agent orchestration service timed out before it completed. This is usually a temporary issue. Wait a moment and try again. This error occurs when: - A reasoning step or AI model call took longer than the allowed time. - A platform dependency was slow or under load when the request was made. ### How to Troubleshoot To resolve this error: 1. Wait at least 2 seconds, then try again. Most timeouts are temporary. 2. If the request consistently times out, try simplifying it: use fewer input variables or a shorter prompt. 3. If retries keep timing out, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `A2A_TIMEOUT` - Whether retries also timed out ## A2A_UNAUTHORIZED The request to the multi-agent orchestration service couldn't be authenticated. The service couldn't verify your identity because authentication credentials were missing or invalid. Retrying without a valid session won't help. This error occurs when: - The request didn't include the expected authentication credentials or session token. - The authentication context was removed by a gateway between your client and the service. - The session token is stale or malformed. ### How to Troubleshoot To resolve this error: 1. Check the detail field in the error response. It identifies which part of the authentication context was missing. 2. Re-authenticate to get a fresh session and try again. 3. If you're connecting through a gateway, verify that authentication headers aren't being stripped in transit. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `A2A_UNAUTHORIZED` - The detail value from the response (which authentication field was missing) ## PLANNER_AGENT_NOT_FOUND The agent identifier in your request couldn't be resolved to an agent that exists and is visible to the caller. No agent work was started. Retrying won't help until the identifier is corrected or access is confirmed. This error occurs when: - The agent identifier is misspelled, truncated, or belongs to a different org. - The agent was deleted or hasn't finished being provisioned. - The agent exists but the caller doesn't have permission to access it. - The request was sent to a different environment than the one the agent is deployed in. ### How to Troubleshoot To resolve this error: 1. Confirm the agent identifier exactly matches the one shown in Setup for the target org. 2. Verify you're calling the environment where the agent is deployed. 3. Confirm the calling user or integration has access to the agent. 4. If the agent was created recently, allow provisioning to finish and try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PLANNER_AGENT_NOT_FOUND` - The environment you called and the approximate time of the request ## PLANNER_INVALID_AGENT_DSL The agent definition supplied with the request didn't conform to the expected schema. The service validates the definition before starting a session and rejected it before any agent work began. Retrying won't help until the definition is corrected. This error occurs when: - A required field is missing from the agent definition, or is present but empty. - A field has the wrong type (for example, a string where an object is expected). - The definition was produced against a different schema version than the one the service accepts. - The definition was truncated or corrupted in transit. ### How to Troubleshoot To resolve this error: 1. Validate your agent definition against the published agent schema before sending it. 2. Check that the definition was serialized completely. Truncation often shows up as a missing trailing field. 3. If you generate the definition programmatically, confirm you're targeting the current schema version. 4. Correct the definition and resend. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PLANNER_INVALID_AGENT_DSL` - The schema version your definition targets ## PLANNER_INVALID_USER_INPUT_FIELDS This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PLANNER_INVALID_USER_INPUT_FIELDS` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## PLANNER_LLM_GATEWAY_AUTH_ERROR This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PLANNER_LLM_GATEWAY_AUTH_ERROR` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## PLANNER_LLM_GATEWAY_BAD_REQUEST This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PLANNER_LLM_GATEWAY_BAD_REQUEST` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## PLANNER_LLM_GATEWAY_EMPTY_GENERATION The language model returned a response with no generated content. The agent couldn't complete the turn with an empty reply, so the request failed. This is usually a temporary issue. Waiting a moment and trying again typically succeeds. This error occurs when: - The model's safety filters suppressed the entire generation. - The prompt left the model with no actionable instruction. - The generation stopped immediately at a stop sequence. ### How to Troubleshoot To resolve this error: 1. Wait at least 2 seconds and try again. Generation is non-deterministic and often succeeds on a second attempt. 2. If the same input consistently returns an empty response, rephrase the user message to be more specific. 3. Review the agent's instructions for stop sequences or constraints that could suppress output. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PLANNER_LLM_GATEWAY_EMPTY_GENERATION` - Whether the same input reproduces the empty response consistently ## PLANNER_LLM_GATEWAY_MALFORMED_RESPONSE This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PLANNER_LLM_GATEWAY_MALFORMED_RESPONSE` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## PLANNER_LLM_GATEWAY_NETWORK_ERROR The service couldn't establish a connection to the language model provider and the request never reached the model. This is usually a temporary issue. Waiting a moment and trying again typically succeeds. This error occurs when: - A temporary connection failure occurred between the service and the model provider. - DNS resolution or TLS negotiation failed momentarily. - A network path or platform component was briefly unavailable. ### How to Troubleshoot To resolve this error: 1. Wait at least 2 seconds and try again. Most connection failures are temporary. 2. If failures persist for more than a few minutes, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PLANNER_LLM_GATEWAY_NETWORK_ERROR` - Whether the failure is intermittent or affecting all requests ## PLANNER_LLM_GATEWAY_RATE_LIMIT The request exceeded the language model capacity allocated to your org. The model provider refused the call. This is a temporary condition. Waiting before retrying typically succeeds. This error occurs when: - A burst of concurrent conversations exhausted your org's model quota. - An automated workload issued requests faster than the allocated rate. - Several agents in the same org competed for the same quota at the same time. ### How to Troubleshoot To resolve this error: 1. Wait at least 5 seconds and try again. 2. If you're running automated or batch workflows, spread requests out over time instead of issuing them all at once. 3. If your org consistently hits this limit during normal use, contact Salesforce Customer Support to discuss your quota. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PLANNER_LLM_GATEWAY_RATE_LIMIT` - Your approximate request rate and how long the throttling has been occurring ## PLANNER_LLM_GATEWAY_SERVICE_UNAVAILABLE The language model provider returned a server-side error or was unreachable, so the agent couldn't generate a response for this turn. This is usually a temporary issue. Waiting before retrying typically succeeds. This error occurs when: - The model provider is experiencing an outage or partial degradation. - The provider is temporarily shedding load during a traffic spike. - A specific model is temporarily unavailable while capacity is rebalanced. ### How to Troubleshoot To resolve this error: 1. Wait at least 5 seconds and try again. 2. If retries keep failing, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. 3. If your agent can use an alternative model, switching may restore service sooner. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PLANNER_LLM_GATEWAY_SERVICE_UNAVAILABLE` - The model your agent is configured to use and the approximate start time of the failures ## PLANNER_LLM_GATEWAY_STREAM_ERROR The model began streaming a response but the stream ended before the response was complete. Any partial content already delivered isn't a valid answer, so the turn failed. This is usually a temporary issue. Trying again typically succeeds. This error occurs when: - The model provider emitted an error partway through generation. - The connection dropped mid-stream. - A streamed event arrived in an unexpected format and couldn't be interpreted. ### How to Troubleshoot To resolve this error: 1. Wait at least 2 seconds and try again. A fresh generation usually completes. 2. If interruptions recur on long responses, consider prompting for a shorter answer. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PLANNER_LLM_GATEWAY_STREAM_ERROR` - Whether any partial content was received before the failure ## PLANNER_LLM_GATEWAY_TIMEOUT The language model didn't respond within the allowed time and the turn was abandoned. This is usually a temporary issue. Waiting a moment and trying again typically succeeds. This error occurs when: - The prompt was unusually large and generation exceeded the time limit. - The model provider was slow under load. - The agent had many agent actions available, which enlarged the request. ### How to Troubleshoot To resolve this error: 1. Wait at least 2 seconds and try again. Most model timeouts are temporary. 2. If timeouts repeat, shorten the conversation input or reduce the number of agent actions available to the agent. 3. If every request times out, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PLANNER_LLM_GATEWAY_TIMEOUT` - How many retries you attempted and whether any succeeded ## PLANNER_MISSING_REQUIRED_HEADER The request reached the service without one or more headers required to identify the org, user, or tenant. The service rejected the request before any agent work began. Retrying the same request won't help until the missing headers are added. This error occurs when: - A required identity header is missing from the request. - A proxy or gateway stripped the header before the request reached the service. - A header was sent with an empty value, which is treated the same as absent. ### How to Troubleshoot To resolve this error: 1. Compare the request headers against the required set for the endpoint you're calling. 2. If you're calling through a proxy or service mesh, confirm it forwards identity headers rather than dropping them. 3. Check for empty-string header values. They don't satisfy the requirement. 4. Resend the request with the complete header set. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PLANNER_MISSING_REQUIRED_HEADER` - The list of headers your client sent (names only, no values) ## PLANNER_MISSING_SESSION_CONTEXT This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PLANNER_MISSING_SESSION_CONTEXT` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## PLANNER_REQUEST_VALIDATION_ERROR The request body didn't match the schema the endpoint expects. Validation runs at the API boundary before any agent work starts. Retrying with the same body won't help. The body must be corrected first. This error occurs when: - A required property is missing from the request body. - A property has the wrong type, such as a string where a number or object is expected. - An enum-valued property was sent with a value outside the accepted set. - The body isn't valid JSON or was truncated in transit. ### How to Troubleshoot To resolve this error: 1. Read the `errors` array in the response. Each entry names the specific field that failed and why. 2. Correct every listed field before resending. Validation reports all failures at once. 3. Validate your payload against the published API schema if failures persist. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PLANNER_REQUEST_VALIDATION_ERROR` - The field names reported in the `errors` array ## PLANNER_SESSION_NOT_FOUND The conversation session referenced in your request isn't in the session store. Sessions are kept for a limited time, so this usually means the session expired, was ended, or the identifier is incorrect. Retrying against the same session won't help. A new session must be started. This error occurs when: - The session exceeded its retention window and was removed. - The session was ended by an earlier request. - The session identifier is misspelled or came from a different environment. - The client reused a session identifier from a previous run. ### How to Troubleshoot To resolve this error: 1. Start a new session and retry the turn against it. 2. If your client caches session identifiers, expire that cache when a session ends. 3. Confirm you're sending the identifier returned by the most recent session-start call for this environment. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PLANNER_SESSION_NOT_FOUND` - How long the session had been idle before the failing request # Agentforce and Generative AI Reference Review the reference documentation for Agentforce and Eintein Generative AI developers. ## Agent API Use Agent API to communicate with AI agents in your org. Create a connected app in your Salesforce org, generate a token, and then start using the API. Take advantage of subagents and actions in Agentforce by sending messages to AI agents. - [Agent API Reference](/docs/ai/agentforce/references/agent-api?meta=Summary) ## Agentforce Python SDK The Agentforce Python SDK lets you programmatically create, manage, and deploy agents and prompt templates in Salesforce. This SDK uses the Salesforce Metadata API from a Python-based implementation that you can incorporate into your solution. - [Agentforce Python SDK Reference](https://github.com/salesforce/agent-sdk/tree/main) ## Agent Script Agent Script is the language for building agents in Agentforce Builder. It combines natural language instructions with programmatic expressions to define agent workflows, business rules, and conversational logic. - [Agent Script Reference](/docs/ai/agentforce/guide/ascript-reference.html) ## Agentforce DX Agentforce DX provides pro-code tools to create and test agents outside the Agentforce Builder UI. - [Agentforce DX Reference](/docs/ai/agentforce/guide/agent-dx-reference.html) ## Agentforce Mobile SDK The Agentforce Mobile SDK provides native iOS and Android integration capabilities for Agentforce conversational AI, enabling developers to embed intelligent agent interactions directly into their mobile applications. - [Agentforce Mobile SDK Reference](/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk) ## Lightning Types Discover how to use custom Lightning types to improve the user interface of custom agent actions for Agentforce in Lightning Experience. Custom Lightning types are particularly effective for handling complex inputs and outputs. - [Lightning Types Reference](/docs/ai/agentforce/guide/lightning-types-references.html) ## Models API The Models API provides Apex classes and REST endpoints that connect your application to large language models (LLMs). - [Models API Apex Reference](/docs/ai/agentforce/references/models-apex-api/models-apex-reference.html) - [Models API REST Reference](/docs/ai/agentforce/references/models-api?meta=Summary) ## Testing API Testing API combines Metadata API and Connect API endpoints to build and run tests on AI agents. - [Testing API Reference](/docs/ai/agentforce/references/testing-api/testing-reference-summary.html) ## Citations Use Apex classes to programatically add citations to agent responses. - [Citations Reference](/docs/ai/agentforce/references/citations/citations-reference.html) ## Metadata and Tooling Some Agentforce functionality is available through our Metadata API and Tooling API. - [Metadata Types](/docs/ai/agentforce/references/agents-metadata-tooling/agents-metadatav67.html) - [Tooling Objects](/docs/ai/agentforce/references/agents-metadata-tooling/agents-tooling.html) ## See Also - [Agentforce Developer Guide](/docs/ai/agentforce/guide/get-started.html) - [Agent API Developer Guide](/docs/ai/agentforce/guide/agent-api.html) - [Models API Developer Guide](/docs/ai/agentforce/guide/models-api.html) # Agentforce Data Library Service Errors The Agentforce Data Library service manages data libraries, sources, retrievers, and file uploads for use in Agentforce agents. Errors from this service typically indicate that a requested resource wasn't found, that a permission or prerequisite is missing, that a request field failed validation, or that a provisioning operation encountered a temporary failure. ## BLOCKED_BY_FAILURE This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `BLOCKED_BY_FAILURE` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## DATA_CATEGORY_DISABLED_WITH_SELECTIONS You can't disable a data category while selections still reference it. Remove all references to the data category first, then retry the disable operation. This error occurs when: - One or more sources still have data category selections that reference the category you're trying to disable. ### How to Troubleshoot To resolve this error: 1. List the sources that currently reference this data category. 2. Remove the data category selections from those sources. 3. Retry the disable operation. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DATA_CATEGORY_DISABLED_WITH_SELECTIONS` ## DATA_CATEGORY_ID_NOT_FOUND The data category ID in your request doesn't exist in this org. Verify the ID and try again. This error occurs when: - The `dataCategoryId` doesn't match any data category in this org. - The data category was deleted after the identifier was captured. - The data category exists in a different org or dataspace than the one being targeted. ### How to Troubleshoot To resolve this error: 1. Look up the data category in Setup and copy the current ID. 2. Verify the request is targeting the correct org and dataspace. 3. Try again with the correct `dataCategoryId`. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DATA_CATEGORY_ID_NOT_FOUND` ## DATA_CATEGORY_MUTUALLY_EXCLUSIVE The data category selections in your request conflict with each other. Choose a non-conflicting combination and try again. This error occurs when: - Two data category selections in the request can't be combined per the category rules. - A parent-child data category relationship makes both selections invalid together. ### How to Troubleshoot To resolve this error: 1. Review the data category rules and identify which selections are mutually exclusive. 2. Choose one non-conflicting combination. 3. Try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DATA_CATEGORY_MUTUALLY_EXCLUSIVE` ## DATA_CATEGORY_NAME_NOT_FOUND The data category name in your request doesn't exist in this org. Data category names are case-sensitive. Verify the name and try again. This error occurs when: - The `dataCategoryName` doesn't match any data category in this org. - There's a typo or casing mismatch in the name. - The data category was renamed after the name was captured. ### How to Troubleshoot To resolve this error: 1. Look up the data category in Setup and copy the current name exactly. 2. Confirm the name's casing matches the value in Setup. 3. Try again with the correct `dataCategoryName`. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DATA_CATEGORY_NAME_NOT_FOUND` ## DATA_CATEGORY_NOT_SUPPORTED The data category configuration you requested isn't supported for this source type. Check which source types accept data category configuration and adjust your request. This error occurs when: - The source type doesn't accept data category configuration. - The requested data category is scoped to a different source type than the one in the request. ### How to Troubleshoot To resolve this error: 1. Check the documentation for which data category configurations each source type supports. 2. Either use a source type that supports the requested configuration, or remove the data category configuration from this source. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DATA_CATEGORY_NOT_SUPPORTED` ## DATA_CATEGORY_RULE_NOT_ENABLED The required data category rule isn't enabled for your org. Ask your Salesforce admin to enable it in Setup, then try again. This error occurs when: - The data category rule is defined but not enabled for the org. - The rule was disabled by an admin after being previously enabled. ### How to Troubleshoot To resolve this error: 1. Ask your Salesforce admin to enable the required data category rule in Setup. 2. Once the rule is enabled, try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DATA_CATEGORY_RULE_NOT_ENABLED` ## DATA_CATEGORY_SELECTION_REQUIRED This operation requires a data category selection, but none was provided. Add a selection and try again. This error occurs when: - The operation depends on a data category selection and none was provided. - The selection was cleared by an earlier update and never restored. ### How to Troubleshoot To resolve this error: 1. Add a data category selection to the request. 2. Try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DATA_CATEGORY_SELECTION_REQUIRED` ## DC1_NOT_SUPPORTED Agentforce Data Library doesn't support companion orgs directly. To connect to a companion org, use a custom retriever instead. This error occurs when: - Your org is a Data 360-enabled companion org, which doesn't support Agentforce Data Library operations. ### How to Troubleshoot To resolve this error: 1. Use a custom retriever to link to the companion org. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DC1_NOT_SUPPORTED` - The org ID ## DC_ASSET_FAILED Data 360 asset provisioning failed. This is usually a temporary issue. Wait a moment and try again. This error occurs when: - A temporary issue occurred during Data 360 asset provisioning. - The provisioning service was temporarily unavailable. ### How to Troubleshoot To resolve this error: 1. Wait a moment and try again. 2. If the error persists, contact Salesforce Customer Support. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DC_ASSET_FAILED` - The approximate time the error occurred (UTC) and the library name or ID the provisioning was targeting ## DC_CONNECTION_MISSING The Data 360 connection isn't active yet. Wait for Data 360 provisioning to complete, then try again. This error occurs when: - Data 360 was just enabled and its connection is still being set up. - The Data 360 connection was interrupted and hasn't reconnected. ### How to Troubleshoot To resolve this error: 1. Wait a few minutes for Data 360 provisioning to complete. 2. Try again once the Data 360 connection is active. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DC_CONNECTION_MISSING` ## DELETE_IN_USE The resource can't be deleted because another resource is currently using it. Remove or update the references first, then try again. This error occurs when: - The resource is referenced by another resource that must be removed or updated first. - A dependent resource still points to this one. ### How to Troubleshoot To resolve this error: 1. Identify the resources that reference this one and remove or update those references first. 2. Try again once no other resource points to it. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DELETE_IN_USE` ## DUPLICATE_CONTENT_FIELDS A content field appears more than once in your request. Each content field must be unique. This error occurs when: - The same content field is listed twice in the request. - Two content field entries resolve to the same underlying field. ### How to Troubleshoot To resolve this error: 1. Remove duplicate content field entries from the request. 2. Confirm each content field is listed exactly once. 3. Try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DUPLICATE_CONTENT_FIELDS` ## DUPLICATE_FILE_NAME Another file with the same name already exists on this source. Use a unique file name and try again. This error occurs when: - A file with the same `fileName` was already uploaded to this source. - A prior upload of the same file didn't complete cleanly and left a partial record. - Two parallel uploads used the same file name. ### How to Troubleshoot To resolve this error: 1. Rename the file locally and retry the upload, or delete the existing file with the same name first. 2. If the duplicate is leftover from a failed upload, remove it before continuing. 3. Try again with a unique `fileName`. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DUPLICATE_FILE_NAME` ## DUPLICATE_PRIMARY_FIELDS More than one field in your request is marked as primary, but only one primary field is allowed. This error occurs when: - Two or more fields in the request are flagged as primary. - A prior primary field wasn't cleared before marking a new one. ### How to Troubleshoot To resolve this error: 1. Review the request and confirm exactly one field is marked as primary. 2. Clear the primary flag on all other fields. 3. Try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DUPLICATE_PRIMARY_FIELDS` ## FEATURE_NOT_ENABLED Agentforce Data Library isn't enabled for your org. Ask your Salesforce admin to enable it, then try again. This error occurs when: - The Agentforce Data Library feature isn't enabled in your org's setup. ### How to Troubleshoot To resolve this error: 1. Ask your Salesforce admin to enable Agentforce Data Library for your org. 2. Once it's enabled, try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `FEATURE_NOT_ENABLED` - The org ID and the operation you were attempting ## FILES_NOT_UPLOADED One or more files referenced in your request aren't present in storage. The upload either didn't start or didn't complete for those files. Waiting and retrying the same request won't create the missing files. You need to upload them again first. This error occurs when: - A file upload URL was obtained but the file was never uploaded to it. - The upload to the file upload URL failed and the failure wasn't surfaced. - The file was uploaded to a different URL than the one referenced in this request. - The `filePath` in the request was copied from a different session and doesn't correspond to a completed upload. ### How to Troubleshoot To resolve this error: 1. Don't retry the same request. Waiting won't create the missing file. 2. Request a fresh file upload URL and upload the file to it. Confirm the upload completed successfully. 3. Reference the newly uploaded file in a new request. 4. If uploads keep failing, verify network connectivity and that the file meets the size and content-type requirements for the upload URL. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `FILES_NOT_UPLOADED` - The `filePath` values that failed, and the upload URL used to try to upload each one (if known) ## FILES_REQUIRED This operation requires at least one file, but none were provided. This error occurs when: - The request omitted the file list entirely. - The file list was present but empty. - An upstream step was expected to attach files and didn't. ### How to Troubleshoot To resolve this error: 1. Attach at least one file to the request. 2. If files come from an upstream step, verify that step produces a non-empty result before this operation runs. 3. Try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `FILES_REQUIRED` ## FILE_LIMIT_EXCEEDED The number of files in this request exceeds the per-request limit. Split the files across multiple requests and try again. This error occurs when: - The request included more files than the per-request maximum. ### How to Troubleshoot To resolve this error: 1. Split the files across multiple requests, keeping each under the maximum file count. 2. Submit the requests separately. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `FILE_LIMIT_EXCEEDED` ## FILE_MIGRATION_FAILED File migration to the upstream store failed. This is usually a temporary issue. Wait a moment and try again. This error occurs when: - A temporary issue occurred during file migration. - The upstream storage service was temporarily unavailable. ### How to Troubleshoot To resolve this error: 1. Wait a moment and try again. 2. If the error persists, contact Salesforce Customer Support. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `FILE_MIGRATION_FAILED` - The approximate time the error occurred (UTC) and the library name or ID and the affected files (if known) ## FILE_NOT_FOUND The file you requested doesn't exist on the specified source. Verify the file identifier and try again. This error occurs when: - The `fileId` in the request doesn't match any file on the target source. - The file was deleted or replaced after the identifier was captured. - The `fileId` is correct but belongs to a different source than the one in the request path. ### How to Troubleshoot To resolve this error: 1. Look up the current files on the target source and copy the correct `fileId`. 2. Confirm the file belongs to the source referenced in the request. 3. Try again with the correct `fileId`. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `FILE_NOT_FOUND` ## FILE_PATH_OWNERSHIP The file path you provided isn't valid for your user context. The path must reference a location within your own Data 360 file storage root. This error occurs when: - The file path points to a location outside your accessible file storage. - The file path belongs to another user's storage area. - A stale or absolute path was used from a different user context. ### How to Troubleshoot To resolve this error: 1. Check that the file path resolves within your own accessible storage area. 2. If you need to share files across users, ask the owning user to reference them from their own context. 3. Try again with a corrected file path. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `FILE_PATH_OWNERSHIP` ## INDEXING_FAILED Document indexing failed for one or more files. This is usually a temporary issue. Wait a moment and try again. This error occurs when: - A temporary issue occurred during document indexing. - The indexing service was temporarily unavailable. ### How to Troubleshoot To resolve this error: 1. Wait a moment and try again. 2. If the error persists, contact Salesforce Customer Support. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INDEXING_FAILED` - The approximate time the error occurred (UTC) and the library name or ID and the affected files (if known) ## INTERNAL_ERROR This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INTERNAL_ERROR` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## INVALID_DESCRIPTION The description you provided exceeds the maximum allowed length. Shorten it and try again. This error occurs when: - The description text is longer than the maximum allowed character count. ### How to Troubleshoot To resolve this error: 1. Shorten the description to fit within the maximum length. 2. Try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_DESCRIPTION` ## INVALID_DEVELOPER_NAME The developer name you provided doesn't meet Salesforce naming rules. Correct the name and try again. This error occurs when: - The `developerName` contains characters other than letters, digits, and underscores. - The name starts with a digit or underscore, or ends with an underscore. - The name exceeds the maximum allowed length. ### How to Troubleshoot To resolve this error: 1. Use only letters, digits, and underscores in the developer name. 2. Start the name with a letter and keep it within the length limit. 3. Try again with a conforming `developerName`. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_DEVELOPER_NAME` ## INVALID_FIELD_NAME The field name you provided isn't valid. Correct it and try again. This error occurs when: - The `fieldName` contains characters that aren't allowed. - The field name doesn't match a known field on the target resource. - There's a typo or casing mismatch in the field name. ### How to Troubleshoot To resolve this error: 1. Check the field naming rules and the target resource's field list. 2. Correct the `fieldName` value. 3. Try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_FIELD_NAME` ## INVALID_FIELD_TYPE The field type you provided for this field isn't supported. Correct it and try again. This error occurs when: - The field type supplied for `fieldName` isn't one of the supported types. - There's a typo or casing mismatch in `fieldType`. - The field type was valid at some point but has since been retired. ### How to Troubleshoot To resolve this error: 1. Check the Agentforce Data Library documentation for the supported field types. 2. Correct the `fieldType` value for the field named `fieldName`. 3. Try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_FIELD_TYPE` ## INVALID_FILE_NAME The file name you provided contains disallowed characters or exceeds the maximum length. This error occurs when: - The `fileName` contains disallowed characters (for example, path separators or control characters). - The name exceeds the maximum allowed length. - The name is empty or consists only of whitespace. ### How to Troubleshoot To resolve this error: 1. Remove disallowed characters from the file name. 2. Shorten the name to fit within the maximum length. 3. Try again with a valid `fileName`. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_FILE_NAME` ## INVALID_INDEX_MODE The index mode you provided isn't supported. Check the supported values and try again. This error occurs when: - The index mode value isn't one of the supported options. - There's a typo or casing mismatch in the index mode value. ### How to Troubleshoot To resolve this error: 1. Check the documentation for the supported index modes. 2. Correct the index mode value. 3. Try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_INDEX_MODE` ## INVALID_MASTER_LABEL The master label you provided is empty or exceeds the maximum allowed length. This error occurs when: - The `masterLabel` field was left blank. - The label exceeds the maximum allowed character length. ### How to Troubleshoot To resolve this error: 1. Provide a non-empty master label. 2. Shorten the label to fit within the maximum length. 3. Try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_MASTER_LABEL` ## INVALID_OFFSET The offset you provided is negative or exceeds the result set size. Provide a valid offset and try again. This error occurs when: - The `offset` is negative. - The `offset` is greater than or equal to the total number of results. - The request is paging past the end of the result set. ### How to Troubleshoot To resolve this error: 1. Set `offset` to a non-negative value less than the total result count. 2. If you're at the end of the result set, stop paging. 3. Try again with a valid `offset`. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_OFFSET` ## INVALID_PAGE_SIZE The page size you provided is outside the valid range. Provide a value between 1 and the maximum page size, then try again. This error occurs when: - The `pageSize` is less than 1 or greater than `maxPageSize`. - The request is paging with a size the server no longer supports. ### How to Troubleshoot To resolve this error: 1. Set `pageSize` to a value between 1 and `maxPageSize` (inclusive). 2. If you need more results, page through them instead of requesting a larger single page. 3. Try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_PAGE_SIZE` ## INVALID_SOURCE_TYPE The source type you provided isn't valid. Check the supported values and try again. This error occurs when: - The `sourceType` value isn't one of the supported types. - There's a typo or casing mismatch in the source type value. - The source type was valid at some point but has since been retired. ### How to Troubleshoot To resolve this error: 1. Check the Agentforce Data Library documentation for the current list of supported source types. 2. Correct the `sourceType` value to one of the supported values. 3. Try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_SOURCE_TYPE` ## INVALID_SOURCE_TYPE_FILTER The source type filter you provided isn't valid. Check the supported filter values and try again. This error occurs when: - The source type filter value isn't one of the supported filter options. - There's a typo or casing mismatch in the filter value. ### How to Troubleshoot To resolve this error: 1. Check the documentation for the supported source type filter values. 2. Correct the filter to a supported value. 3. Try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_SOURCE_TYPE_FILTER` ## INVALID_WAIT_MAX_TIME The wait-max-time value you provided is outside the valid range. Check the supported range and try again. This error occurs when: - The `waitMaxTime` value is negative, zero, or exceeds the maximum allowed. - A unit conversion mistake put the value in the wrong range (for example, milliseconds instead of seconds). ### How to Troubleshoot To resolve this error: 1. Check the documentation for the supported `waitMaxTime` range. 2. Set `waitMaxTime` to a value within the supported range. 3. Try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_WAIT_MAX_TIME` ## LIBRARY_ALREADY_EXISTS A library with the name or identifier you provided already exists. Choose a different name or identifier and try again. This error occurs when: - The `libraryName` matches an existing library in this org. - A prior create attempt succeeded partially and left an existing record. ### How to Troubleshoot To resolve this error: 1. Choose a unique `libraryName` and try again. 2. If a prior create was expected to fail, check whether the library was actually created and reuse it instead of creating a new one. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `LIBRARY_ALREADY_EXISTS` ## LIBRARY_NOT_FOUND The data library you requested doesn't exist in this org. Verify the library identifier and try again. This error occurs when: - The `libraryId` in the request doesn't match any library in this org. - The library was deleted or renamed after the identifier was captured. - The request is being sent to a different org than the one where the library exists. ### How to Troubleshoot To resolve this error: 1. Look up the library in Agentforce and copy the current identifier. 2. Verify the request is targeting the same org the library belongs to. 3. Try again with the correct `libraryId`. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `LIBRARY_NOT_FOUND` ## MISMATCH_SOURCE_TYPE The source type in your request doesn't match the source type the existing source was created with. You can't change a source's type after creation. This error occurs when: - The request is trying to update an existing source with a different source type than it was created with. - The `sourceType` field was accidentally changed on an update call. ### How to Troubleshoot To resolve this error: 1. Look up the existing source's type and match it in the request. 2. If you need a different source type, delete the existing source and create a new one with the desired type. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `MISMATCH_SOURCE_TYPE` ## MISSING_ORG_PREREQUISITE Your org doesn't satisfy a required prerequisite for this operation. Ask your Salesforce admin to review and configure the prerequisites, then try again. This error occurs when: - Your org is missing a required permission, license, or dependent feature needed for this operation. ### How to Troubleshoot To resolve this error: 1. Ask your Salesforce admin to review the org's Agentforce Data Library prerequisites and enable any missing ones (for example, required org permissions, license provisioning, or dependent features). 2. Once the prerequisite is in place, try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `MISSING_ORG_PREREQUISITE` - The org ID and the operation you were attempting ## MISSING_REQUIRED_FIELD A required field is missing from your request. Add the field and try again. This error occurs when: - The `fieldName` shown in the error was omitted from the request. - The field was present but set to an empty string or null. - A typo in the field key caused the field to be skipped. ### How to Troubleshoot To resolve this error: 1. Add the required field (`fieldName`) to the request body. 2. Provide a non-empty value for the field. 3. Try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `MISSING_REQUIRED_FIELD` ## NON_DEFAULT_DATASPACE Agentforce Data Library operations are only supported in the default dataspace. There's no configuration change that enables it in non-default dataspaces. This error occurs when: - The request is targeting a non-default dataspace, which isn't supported by Agentforce Data Library. ### How to Troubleshoot To resolve this error: 1. Switch the request context to the default dataspace and try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `NON_DEFAULT_DATASPACE` - The dataspace and org ID ## OVERLAPPING_CONTENT_FIELD A content field in your request overlaps with another already configured on this source. Choose a non-overlapping field or remove the existing configuration first. This error occurs when: - The new content field resolves to the same underlying data as an already-configured content field. - Two content fields cover the same field path with different labels. ### How to Troubleshoot To resolve this error: 1. Review the existing content fields on the source and identify the overlap. 2. Choose a non-overlapping content field, or remove the existing configuration before adding the new one. 3. Try again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `OVERLAPPING_CONTENT_FIELD` ## PERMISSION_DENIED You don't have permission to perform this operation on the specified Agentforce Data Library resource. Contact your Salesforce admin to grant access. This error occurs when: - The acting user doesn't have the permission required for this Agentforce Data Library operation. ### How to Troubleshoot To resolve this error: 1. Ask your Salesforce admin to grant the permission required for Agentforce Data Library operations on the affected resource. 2. Confirm you're authenticated as the correct user before trying again. The permission is checked against the acting user, not the org. 3. If access was recently granted, sign out and sign back in so the session picks up the updated permissions. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PERMISSION_DENIED` - The Salesforce user and the resource you were trying to access ## PRIMARY_FIELDS_IMMUTABLE Primary fields can't be modified after a source is created. If you need a different primary field, delete and recreate the source. This error occurs when: - The update request tries to change which field is marked primary on an existing source. - The primary field configuration was regenerated on the client and no longer matches the source. ### How to Troubleshoot To resolve this error: 1. Keep the existing primary field configuration on the source. 2. If you need a different primary field, delete and recreate the source with the desired configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PRIMARY_FIELDS_IMMUTABLE` ## PROVISIONING_IN_PROGRESS Library provisioning is still in progress. Wait a few minutes and try again. This error occurs when: - The library was recently created and its backing infrastructure is still being provisioned. - Provisioning is running longer than usual for this org. ### How to Troubleshoot To resolve this error: 1. Wait a few minutes and try again. 2. Poll the library's status until it reaches the ready state before proceeding. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PROVISIONING_IN_PROGRESS` ## RETRIEVER_FAILED Retriever provisioning failed. This is usually a temporary issue. Wait a moment and try again. This error occurs when: - A temporary issue occurred during retriever provisioning. - The provisioning service was temporarily unavailable. ### How to Troubleshoot To resolve this error: 1. Wait a moment and try again. 2. If the error persists, contact Salesforce Customer Support. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `RETRIEVER_FAILED` - The approximate time the error occurred (UTC) and the library name or ID the retriever provisioning was targeting ## RETRIEVER_NOT_ACTIVE The retriever you requested is currently inactive. Activate it before issuing this request. This error occurs when: - The retriever exists but is in an inactive state. - The retriever was deactivated by an admin after being previously active. ### How to Troubleshoot To resolve this error: 1. Activate the retriever in Agentforce. 2. Try again once the retriever is active. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `RETRIEVER_NOT_ACTIVE` ## RETRIEVER_NOT_FOUND The retriever you requested doesn't exist. Verify the retriever identifier and try again. This error occurs when: - The `retrieverId` in the request doesn't match any retriever in this org. - The retriever was deleted after the identifier was captured. - The request is being sent to a different org than the one where the retriever exists. ### How to Troubleshoot To resolve this error: 1. Look up the retriever in Agentforce and copy the current `retrieverId`. 2. Verify the request is targeting the correct org. 3. Try again with the correct `retrieverId`. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `RETRIEVER_NOT_FOUND` ## SEARCH_INDEX_FAILED Search index provisioning failed. This is usually a temporary issue. Wait a moment and try again. This error occurs when: - A temporary issue occurred during search index provisioning. - The provisioning service was temporarily unavailable. ### How to Troubleshoot To resolve this error: 1. Wait a moment and try again. 2. If the error persists, contact Salesforce Customer Support. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `SEARCH_INDEX_FAILED` - The approximate time the error occurred (UTC) and the library name or ID the search index provisioning was targeting ## SEARCH_INDEX_QUOTA_EXCEEDED Your org has reached the maximum number of search indexes allowed. Delete unused indexes to free up space, then try again. This error occurs when: - The org already has the maximum permitted number of search indexes. - An older, no-longer-needed index is still occupying a slot. ### How to Troubleshoot To resolve this error: 1. Identify any search indexes that are no longer needed and delete them. 2. Try again once a slot is available. 3. If your workflow requires more indexes than the current quota allows, contact Salesforce Customer Support to discuss options. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `SEARCH_INDEX_QUOTA_EXCEEDED` ## SOURCE_NOT_FOUND The data source you requested doesn't exist on the specified library. Verify the source identifier and try again. This error occurs when: - The `sourceId` in the request doesn't match any source on the target library. - The source was deleted, or a stale identifier is still in use. - The `sourceId` is correct but belongs to a different library than the one in the request path. ### How to Troubleshoot To resolve this error: 1. Look up the current sources on the target library and copy the correct `sourceId`. 2. Confirm the source belongs to the library referenced in the request. 3. Try again with the correct `sourceId`. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `SOURCE_NOT_FOUND` ## UNSUPPORTED_FILE_TYPE The file type you provided isn't supported by Agentforce Data Library. Convert the file to a supported format and try again. This error occurs when: - The file's extension isn't on the supported file type list. - The file was renamed with an extension that misrepresents its actual content. ### How to Troubleshoot To resolve this error: 1. Check the documentation for the supported file types. 2. Convert the file to a supported format, or exclude it from this operation. 3. Try again with only supported file types. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `UNSUPPORTED_FILE_TYPE` ## UNSUPPORTED_SOURCE_TYPE The source type you provided isn't currently supported by Agentforce Data Library. This error occurs when: - The source type is recognized as a valid identifier but isn't yet enabled for Agentforce Data Library. - The source type has been deprecated for Agentforce Data Library use. ### How to Troubleshoot To resolve this error: 1. Check the Agentforce Data Library documentation for the currently supported source types. 2. Choose a supported source type for this operation. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `UNSUPPORTED_SOURCE_TYPE` ## UPDATE_IN_PROGRESS An update is already in progress on this resource. Wait for it to finish and try again. This error occurs when: - A previous update on the same resource hasn't finished yet. - Two clients issued updates against the same resource at the same time. ### How to Troubleshoot To resolve this error: 1. Wait for the in-progress update to finish before trying again. 2. If the update appears stuck, check the resource's status to confirm it eventually reaches a terminal state. 3. Try again once the resource is idle. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `UPDATE_IN_PROGRESS` ## UPLOAD_NOT_READY The upload isn't ready for the requested operation yet. Wait for the upload to complete and try again. This error occurs when: - The upload was still in progress when the follow-up operation ran. - The request ran too soon after the upload started. ### How to Troubleshoot To resolve this error: 1. Wait for the upload to reach the ready state before running the follow-up operation. 2. Check the upload status periodically. Wait a moment between checks. 3. Try again once the upload is ready. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `UPLOAD_NOT_READY` ## UPLOAD_NOT_READY_TIMEOUT The upload didn't become ready before the wait-max-time expired. Wait a while and try again. The upload may still complete on its own. This error occurs when: - The upload took longer than the configured `waitMaxTime`. - The upload is still in progress and just needs more time. ### How to Troubleshoot To resolve this error: 1. If the upload is expected to take longer, increase `waitMaxTime` for this operation. 2. Wait and try again. The upload may complete on its own. 3. If the upload never completes, contact Salesforce Customer Support. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `UPLOAD_NOT_READY_TIMEOUT` # Agentforce DX Agentforce DX provides pro-code tools to create and test agents outside the Agentforce Builder UI. - [Agentforce DX Reference](/docs/ai/agentforce/guide/agent-dx-reference.html) # Agentforce DX Reference Reference information for Agentforce DX YAML files. ## Salesforce CLI Command Reference For a list of CLI commands for agents, see [Salesforce CLI Command Reference](https://developer.salesforce.com/docs/platform/salesforce-cli-reference/guide/cli_reference_agent.html). ## Metadata Reference - [Agentforce Metadata Types](/docs/ai/agentforce/references/agents-metadata-tooling/agents-metadatav67.html): Reference for agent metadata types and structure used with the Metadata API. ## Agent Spec File Reference This table lists the properties that you can include in the agent spec YAML file. You use this YAML file to create an agent with the `agent create` command. See [Agent Spec File Example](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-generate-agent-spec.md#agent-spec-file-example) for a full example. | Property Name | Required? | Equivalent `agent generate agent-spec` Flag Name | Description | | :------------------- | :-------- | :----------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `agentType` | Yes | `--type` | The type of agent that you want to create. Valid values:
  • `customer`: The agent interacts with your customers.
  • `internal`: The agent interacts with your employees.

**Example:**

`agentType: customer` | | `companyName` | Yes | `--company-name` | The name of your company.

**Example:**

`companyName: Coral Cloud Resorts` | | `companyDescription` | Yes | `--company-description` | A natural language description of your company.

**Example:**

`companyDescription: Provides customers with exceptional destination activities and unforgettable experiences.` | | `role` | Yes | `--role` | A natural language description of the role that the agent plays in your company and what tasks it can perform.

**Example:**

`role: Fields customer complaints, manages employee schedules, and generally makes sure everything is working smoothly.` | | `maxNumOfTopics` | No | `--max-topics` | The maximum number of subagents that the LLM generates when you run `agent generate agent-spec`. The default value is 5.

**Example:**

`maxTopics: 10` | | `agentUser` | No | `--agent-user` | The username of a user in your org to which to assign your agent. This assignment determines what your agent can access and do. Be sure you provide the required permissions to this user. The username must exist in your org.

To learn more about permissions, start with [Give Users Access to the Default Agentforce Agent](https://help.salesforce.com/s/articleView?id=ai.copilot_setup_user_access.htm&type=5).

**Example:**

`agentUser: managerrole@salesforce.com` | | `enrichLogs` | No | `--enrich-logs` | Adds agent conversation data to event logs so that you can view all agent session activity in one place. The default value is `false`.

**Example:**

`enrichLogs: true` | | `tone` | No | `--tone` | The conversational style of the agent, such as how it expresses your brand personality in its messages through word choice, punctuation, and sentence structure. Possible values are `casual` (default), `formal`, and `neutral`.

See [Language Settings](https://help.salesforce.com/s/articleView?id=ai.copilot_setup_tone.htm&type=5).

**Example:**

`tone: formal` | | `promptTemplateName` | No | `--prompt-template` | The API name of a customized prompt template that the agent uses instead of the default template. Prompt templates are reusable, detailed prompts that help the LLM generate a high-quality response when a user uses your agent. The prompt template can include placeholders for information that changes, such as customer names, contact information, and product prices.

To find the API name of your prompt template, go to Prompt Builder in your org, select the template name, and then open its settings.

See [Get to Know Prompt Builder](https://help.salesforce.com/s/articleView?id=ai.prompt_builder_get_to_know.htm&type=5).

**Example:**

`promptTemplateName: einstein_gpt__answerWithKnowledge` | | `groundingContext` | No | `--grounding-context` | Context information and personalization that's added to your agent’s prompts when using a custom prompt template.

See [Ground Prompt Templates with Salesforce Resources](https://help.salesforce.com/s/articleView?id=ai.prompt_builder_ground_template.htm&type=5) for Salesforce-specific examples of grounding contexts.

**Example:**

`groundingContext: You are a resort manager and you need to create a schedule for the {!$Input:User.Name} employee.` | | `topics` | Yes | None | A list of subagents generated by the LLM based on the agent properties.

**Example:**
 topics:
- name: Customer Complaint Resolution
description: Automate customer complaints.
- name: Employee Schedule Management
description: Optimize employee scheduling.
| ## Agent Test Spec File Reference **warning:** This section describes the legacy process for testing Agentforce agents, or the pro-code equivalent to using the [Legacy Agentforce Testing Center in Setup](https://help.salesforce.com/s/articleView?id=ai.agent_testing_center_setup_tests.htm&type=5). It doesn't apply to the new agent testing process, or the pro-code equivalent to the [New Testing Center in Agentforce Studio (Beta)](https://help.salesforce.com/s/articleView?id=ai.agent_studio_testing_center_setup_tests.htm&type=5). That documentation will be released soon. This table lists the properties that you can include in the agent test spec YAML file. You use this YAML file to create an agent test with the `agent test create` command. See [Generate a Test Spec File](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-test-spec.md) for a full example. | Property Name | Required? | Description | | :-------------------------- | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | Yes | The name (label) of the test.

**Example:**

`name: Resort Manager Tests` | | `description` | No | The purpose of the test.

**Example:**

`description: Tests for the Resort Manager agent.` | | `subjectType` | Yes | The type of subject being tested. The only currently supported value is `AGENT`. | | `subjectName` | Yes | The API name of the agent, which you can find on the agent details page in Setup.

**Example:**

`subjectName: Resort_Manager` | | `subjectVersion` | No | The agent version to test. If not provided, the latest active version is used by default. You can find the version in the BotVersion metadata type.

**Example:**

`subjectVersion: v1` | | `testCases` | Yes | List of one or more test cases.

**Example:**
testCases:
- utterance: Who is working the front desk today at noon?
expectedTopic: p_16jQP0000000PEX_Employee_Sched_Manage
expectedActions:
- EmployeeCopilot\_\_CreateAToDo
expectedOutcome: Anna is working the desk.
| | `testCases.utterance` | Yes | A natural language statement, question, or command to test the agent.

**Example:**

`- utterance: Who is working the front desk today at noon?` | | `testCases.expectedTopic` | Yes | The API name of the subagent that you expect the agent to use when it responds to the utterance.

**Example:**

`expectedTopic: p_16jQP0000000PEX_Employee_Sched_Manage` | | `testCases.expectedActions` | Yes | The API name of one or more actions associated with the subagent that you expect the agent to use.

**Example:**
 expectedActions:
- EmployeeCopilot**CreateAToDo
- EmployeeCopilot**UpdateSchedule
| | `testCases.expectedOutcome` | Yes | A natural language description of the expected outcome of the test case.

**Example:**

`expectedOutcome: Anna is working the desk.` | # Agentforce Example: Customer Support Agent This example builds a customer support agent that verifies a customer's identity and helps them get information about their orders. You can build the same agent in three different ways (Headless, Script, or Canvas). [Choose the path](#choose-your-path) that fits how you work. ### Subagent Summary The agent contains three subagents: - The `agent_router` subagent, which provides general instructions to the LLM and exposes two tools that the LLM can select to call. The two tools are utilities that transition to the required subagents, based on user input. - The `Identity` subagent, which verifies the user's identity. This subagent allows the LLM to request the user's email (if it doesn't exist), then sends a verification code to the provided email. Then, the LLM can validate the verification code that the customer provides. This subagent contains deterministic tools and actions, while allowing the LLM freedom to use natural language to interact with the user. - The `Order_Management` subagent, which allows the user to look up order details. ### Prerequisites Before you build the agent on any path, make sure that your org is ready: - **Einstein and Agentforce are enabled.** See [Set Up Einstein and Agentforce](https://developer.salesforce.com/docs/ai/org-setup.md). - **You have an active user for the agent.** Every agent runs as a specific user. These examples use `agentforce@salesforce.com` as a placeholder for the `default_agent_user` — replace it with an active Einstein Agent User in your own org. To find one, in Setup go to **Users**, or query `SELECT Username FROM User WHERE UserType = 'EinsteinAgent' AND IsActive = true`. - **The flows the agent calls exist in your org.** See [Flows This Agent Calls](#flows-this-agent-calls). If they don't exist yet, stub them so you can preview the agent end-to-end. - For the Headless and Script paths, **the Salesforce CLI must be installed and authorized to your org**. See [Set Up Your DX Environment](https://developer.salesforce.com/docs/ai/agentforce/agent-dx/agent-dx-set-up-env.md). ### Flows This Agent Calls No matter which path you select, this agent calls four flows to do its work. The agent expects them to exist in your org. These names are the example's defaults. If you point an action at a different flow, keep its input and output variable names the same so the action's contract still matches. | Flow | Called to… | Inputs | Outputs | | ---------------------------- | ------------------------------------------ | ------------------------ | ---------------------------------- | | `Get_Verification_Code` | Send a verification code by email | `email`, `member_number` | `verification_code`, `member_name` | | `validate_Verification_Code` | Confirm the code that the customer entered | `verification_code` | `verification` (boolean) | | `Get_Current_Order` | Look up the customer's current order | `member_email` | `order_summary`, `order_id` | | `Get_Past_Order` | Look up a past order by ID | `query` | `order_summary`, `order_id` | All four flows are specific to this example. (In a real Service Cloud org, the order lookups are often handled by standard `SvcCopilotTmpl__` flows instead. That namespace is reserved for a managed package, so this example uses its own plainly named flows that any org can create.) If a flow doesn't exist in your org, the agent won't publish — a flow action can't point at a `flow://` target that isn't there. To try the agent end-to-end without wiring up real backends, replace each flow with a **stub**: an autolaunched flow that ignores its inputs and returns canned values. A stub flow needs only three things: 1. **Input variables** that match the action's inputs (marked _Available for input_), so the agent can pass values in. 2. **Output variables** that match the action's outputs (marked _Available for output_), so the agent can read results back. 3. **An Assignment element** that sets each output variable to a fixed value. For example, a `validate_Verification_Code` stub takes a `verification_code` input, ignores it, and assigns `true` to a `verification` output — so any code the customer enters passes. A `Get_Verification_Code` stub returns a fixed `verification_code` (such as `123456`) and a `member_name`. Give each stub the exact flow name and variable names from the table above, deploy it (`sf project deploy start`), then build the agent. ### Choose Your Path You can build this agent three ways. Select a tab to follow that path from start to finish. | If you're a… | You'll build with… | Open the tab… | | ------------------------------------- | --------------------------------------------------------------------------------- | ------------- | | **Vibe coder** (instruct an AI agent) | Natural-language prompts to an AI coding agent, no platform UI required | **Headless** | | **Developer** (code) | Agent Script in Script view, [Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/agent-dx/agent-dx.md), or the CLI | **Script** | | **Admin** (clicks, not code) | Agentforce Builder Canvas view | **Canvas** |
::::::tabset{tabs='["Headless", "Script", "Canvas"]'} :::::tab Build the agent by describing what you want in natural language and letting an AI coding agent generate the metadata for you — no platform UI required. To get reliable results, use a coding agent that has Salesforce development context loaded, so it follows platform best practices and produces valid Agent Script. - [Agentforce Vibes](https://developer.salesforce.com/docs/platform/agentforcevibes/guide/afv-overview.html) is Salesforce's AI-assisted development tool, built for headless development on the platform. - The [Salesforce Skills Library](https://github.com/forcedotcom/sf-skills) provides skills you can add to any coding agent that supports them, so the agent follows Salesforce best practices. - If you're building your own AI solution, add the Agent Script documentation set as context. See [Download the Agent Script Documentation](https://developer.salesforce.com/docs/ai/agentforce/agent-script/ascript-download-documentation.md). With this context in place, paste the prompt from each step below into your coding agent. The more specific your prompt — naming the agent's behavior, the rules it must follow, and any flows or actions it needs to call — the closer the result matches. ### Headless Step 1: Scaffold the Agent This prompt sets up the agent's foundation — its name, instructions, welcome message, running user, and locale. ``` Build an Agentforce customer support agent in Agent Script, with the developer name pronto_customer_support_assistant. Its job is to help customers get information about their orders while following professional support policies. Set the welcome message to "Hi there, I'm your Pronto Customer Support Assistant," use agentforce@salesforce.com as the default agent user, and set the locale to en_US. ``` ### Headless Step 2: Define the Variables When you build headlessly, you don't hand-write variable declarations or specify Agent Script types — but do name the variables explicitly, so they match the references in the prompts for later steps. ``` Define the agent's variables using these exact names. For identity: member_name, member_email, member_number, verification_code (the code the agent sends), user_verification_code (the code the customer enters), and a verified boolean that defaults to False and gates access to order lookups. For orders: order_id and an order_summary string that starts empty. You don't need to specify types — just name each variable and describe what it holds. ``` ### Headless Step 3: Build the Router This prompt creates the router subagent — the agent's entry point that welcomes the customer and routes them to the right subagent based on whether they're verified. ``` Add a start_agent router subagent that welcomes the customer and decides which subagent should handle their request. Give it two transition tools, gated by the verified variable: a transition to the Identity subagent available only when verified is False, and a transition to the Order Management subagent available only when verified is True. Tell it to never escalate to a human unless the customer explicitly asks. ``` ### Headless Step 4: Build the Identity Subagent This prompt creates the Identity subagent, which verifies the customer by email before any order data is exposed, calling flows to send and validate a verification code. ``` Add an Identity subagent that verifies the customer before they can look up orders. When member_email is known, send a verification code by calling the Get_Verification_Code flow and store its outputs in verification_code and member_name. Ask the customer for the code they received, save it in user_verification_code, and validate it by calling the validate_Verification_Code flow, setting the verified variable from the result. If they didn't get the code, confirm their email and resend it. Once verified is True, allow a transition to the Order Management subagent. ``` ### Headless Step 5: Build the Order Management Subagent This prompt creates the Order Management subagent, which automatically looks up the customer's current order on entry and can also retrieve a past order by ID. ``` Add an Order Management subagent. When the customer enters this subagent and the order_summary variable is empty, automatically run a lookup of their current order by email (backed by the Get_Current_Order flow) and store the result in order_summary. Address the customer by name and show their order summary. If they ask about a past order, request the Order ID and look it up with the Get_Past_Order flow. ``` ### Headless Step 6: Preview and Test Deploy the agent to your org with the Salesforce CLI or your coding agent's MCP connection, then open it in Agentforce Builder and select **Preview**. Start a conversation, such as _I need help with my order_, and confirm the agent asks you to verify your identity first. ::::: :::::tab Build the agent by writing Agent Script directly in Script view, in [Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/agent-dx/agent-dx.md), or with the CLI. The snippets below assemble into the complete script in [The Complete Script](#the-complete-script) at the end of this tab. ### Script Step 1: Scaffold the Agent Set up the agent's foundation. This Agent Script snippet defines the `system` block (the agent's instructions and welcome and error messages), the `config` block (developer name and description), the `access` block (the default agent user), and the `language` block (locale settings). ```agentscript system: instructions: "You are a helpful, professional assistant that provides customers with information about their orders." messages: welcome: "Hi there, I'm your Pronto Customer Support Assistant." error: "Sorry, something went wrong on my end. Could you say that again in a different way?" config: developer_name: "pronto_customer_support_assistant" description: "Assists customers with their orders while following defined support policies." access: default_agent_user: "agentforce@salesforce.com" language: default_locale: "en_US" additional_locales: "" all_additional_locales: False ``` **note:** Replace `agentforce@salesforce.com` with an active Einstein Agent User in your org. The agent won't publish with a `default_agent_user` that doesn't exist. See [Prerequisites](#prerequisites). ### Script Step 2: Define the Variables Declare the variables that the agent uses to remember information across the conversation. This Agent Script snippet declares them in a `variables` block, grouped into identity variables (such as `member_email` and the `verified` boolean) and order variables (such as `order_summary`). Each variable is `mutable`, so the agent can update it during the conversation, and some have default values. ```agentscript variables: # Identity member_name: mutable string description: "This is the name of the member." member_email: mutable string = "" description: "This is the email address of the member." member_number: mutable string description: "This is the member number for identification." verification_code: mutable string description: "This is the verification code to validate against the user's." user_verification_code: mutable string description: "This is the verification code entered by the user." verified: mutable boolean = False description: "Shows whether or not the user's identity has been verified." # Orders order_id: mutable string description: "This is the Order ID of the order they placed." order_summary: mutable string = "" description: "This is the summary of the order." ``` ### Script Step 3: Build the Router Add the `agent_router` subagent as the agent's entry point. This Agent Script snippet defines the `start_agent` subagent with a `reasoning` block. The reasoning instructions tell the LLM how to greet and route the customer, and the `actions` section exposes two `@utils.transition` tools, each gated by an `available when` condition on the `verified` variable, so customers must verify before they can look up orders. ```agentscript # The entry point for the agent, on every customer utterance. start_agent agent_router: description: "Welcome the user and determine the appropriate subagent based on user input" reasoning: instructions: -> | You are an agent router for a Customer Service Bot assistant. Welcome the guest and analyze their input to determine the most appropriate subagent to handle their request. NEVER escalate to a human unless explicitly requested. A bad experience shouldn't automatically escalate. # This section lists the tools that the LLM # can choose to use. In this example, the LLM has two tools: # transitioning to the Identity subagent or transitioning to the # Order_Management subagent actions: # Transitions deterministically route execution to the specified subagent. # Once the LLM chooses to use this tool, the execution is guaranteed # to transition. go_to_identity: @utils.transition to @subagent.Identity description: "verifies user identity" available when @variables.verified == False go_to_order: @utils.transition to @subagent.Order_Management description: "Handles order lookup, refunds, order updates, and summarizes status, order date, current location, delivery address, items, and driver name." available when @variables.verified == True ``` ### Script Step 4: Build the Identity Subagent Add the `Identity` subagent, which verifies the customer before any order data is exposed. This Agent Script snippet defines the subagent: the `reasoning` block runs `send_verification_code` deterministically when an email exists, then guides the LLM to validate the code, while the `reasoning.actions` section exposes the two verification actions and a transition tool. The subagent's own `actions` section defines `send_verification_code` and `validate_verification_code`, each targeting a flow. ```agentscript subagent Identity: description: "Handles verification of the user's identity before providing access to all other topics." reasoning: instructions: -> if @variables.member_email != "": run @actions.send_verification_code with email=@variables.member_email with member_number = @variables.member_number set @variables.verification_code=@outputs.verification_code set @variables.member_name=@outputs.member_name | Greet the user and inform them that to help them get started you've sent them a verification code via email. # This prompt contains two actions that the LLM can choose to run - # a tool to send the verification code, and a tool to validate the # verification code. Once the LLM chooses to run these actions, # the actions are run deterministically Ask the user for the verification code they received and verify it using {!@actions.validate_verification_code}. If the user says they did not receive the code, ask them to confirm their email and resend the verification code using {!@actions.send_verification_code} # The reasoning.actions section declares the tools that the LLM can choose # to run. This section has three tools - two actions and # one transition. actions: send_verification_code: @actions.send_verification_code with email=@variables.member_email with member_number=@variables.member_number set @variables.verification_code=@outputs.verification_code validate_verification_code: @actions.validate_verification_code available when @variables.verification_code != None with verification_code=@variables.user_verification_code set @variables.verified=@outputs.verification go_to_order_management: @utils.transition to @subagent.Order_Management available when @variables.verified == True # This section defines the actions available to this subagent. Actions are # only valid within the subagent in which they are defined. actions: send_verification_code: description: "Send a verification code to the member and verify confirmation." inputs: email: string member_number: string outputs: verification_code: string member_name: string target: "flow://Get_Verification_Code" validate_verification_code: description: "validate the verification code" inputs: verification_code: string outputs: verification: boolean description: "always validate and return True" target: "flow://validate_Verification_Code" ``` ### Script Step 5: Build the Order Management Subagent Add the `Order_Management` subagent, which looks up order details. This Agent Script snippet defines the subagent: the `reasoning` block runs `lookup_current_order` when `order_summary` is empty and stores the result in variables, and the `reasoning.actions` section exposes both lookup actions. The subagent's `actions` section defines `lookup_order` and `lookup_current_order`, each targeting a flow. ```agentscript subagent Order_Management: description: "Handles order lookup, order updates, and summaries including status, date, location, items, and driver." reasoning: instructions: -> if @variables.order_summary == "": run @actions.lookup_current_order with member_email=@variables.member_email set @variables.order_summary=@outputs.order_summary | Refer to the user by name {!@variables.member_name}. Show their current order summary: {!@variables.order_summary} when conversation starts or if requested. If they want past order info, ask for Order ID and use {!@actions.lookup_order}. actions: # The ... indicates that the LLM can use reasoning to select the # information from the customer's conversation, then input # the information into the correct input variables lookup_order: @actions.lookup_order with query = ... # Store the action's output into variables set @variables.order_summary=@outputs.order_summary set @variables.order_id=@outputs.order_id lookup_current_order: @actions.lookup_current_order with member_email=@variables.member_email set @variables.order_summary=@outputs.order_summary set @variables.order_id=@outputs.order_id actions: lookup_order: description: "Retrieve order details." inputs: query: string outputs: order_summary: string order_id: string target: "flow://Get_Past_Order" lookup_current_order: description: "Retrieve current order details." inputs: member_email: string outputs: order_summary: string order_id: string target: "flow://Get_Current_Order" ``` ### Script Step 6: Preview and Test In Script view, select **Preview** and start a conversation, such as _I need help with my order_. Confirm that the agent asks you to verify your identity first, and that order details return correctly after verification. **tip:** - Each agent needs a unique `developer_name`. If you make multiple agents from one example script, change the developer name each time. - If you encounter an unexpected error in Agentforce Builder with the last line of your script, add a blank line or a comment to the end. ### The Complete Script The snippets from Steps 1–5 combine into this complete script. Copy and paste it to create the agent in one shot. ```agentscript system: instructions: "You are a helpful, professional assistant that provides customers with information about their orders." messages: welcome: "Hi there, I'm your Pronto Customer Support Assistant." error: "Sorry, something went wrong on my end. Could you say that again in a different way?" config: developer_name: "pronto_customer_support_assistant" description: "Assists customers with their orders while following defined support policies." access: default_agent_user: "agentforce@salesforce.com" variables: # Identity member_name: mutable string description: "This is the name of the member." member_email: mutable string = "" description: "This is the email address of the member." member_number: mutable string description: "This is the member number for identification." verification_code: mutable string description: "This is the verification code to validate against the user's." user_verification_code: mutable string description: "This is the verification code entered by the user." verified: mutable boolean = False description: "Shows whether or not the user's identity has been verified." # Orders order_id: mutable string description: "This is the Order ID of the order they placed." order_summary: mutable string = "" description: "This is the summary of the order." language: default_locale: "en_US" additional_locales: "" all_additional_locales: False # The entry point for the agent, on every customer utterance. start_agent agent_router: description: "Welcome the user and determine the appropriate subagent based on user input" reasoning: instructions: -> | You are an agent router for a Customer Service Bot assistant. Welcome the guest and analyze their input to determine the most appropriate subagent to handle their request. NEVER escalate to a human unless explicitly requested. A bad experience shouldn't automatically escalate. # This section lists the tools that the LLM # can choose to use. In this example, the LLM has two tools: # transitioning to the Identity subagent or transitioning to the # Order_Management subagent actions: # Transitions deterministically route execution to the specified subagent. # Once the LLM chooses to use this tool, the execution is guaranteed # to transition. go_to_identity: @utils.transition to @subagent.Identity description: "verifies user identity" available when @variables.verified == False go_to_order: @utils.transition to @subagent.Order_Management description: "Handles order lookup, refunds, order updates, and summarizes status, order date, current location, delivery address, items, and driver name." available when @variables.verified == True subagent Identity: description: "Handles verification of the user's identity before providing access to all other topics." reasoning: instructions: -> if @variables.member_email != "": run @actions.send_verification_code with email=@variables.member_email with member_number = @variables.member_number set @variables.verification_code=@outputs.verification_code set @variables.member_name=@outputs.member_name | Greet the user and inform them that to help them get started you've sent them a verification code via email. # This prompt contains two actions that the LLM can choose to run - # a tool to send the verification code, and a tool to validate the # verification code. Once the LLM chooses to run these actions, # the actions are run deterministically Ask the user for the verification code they received and verify it using {!@actions.validate_verification_code}. If the user says they did not receive the code, ask them to confirm their email and resend the verification code using {!@actions.send_verification_code} # The reasoning.actions section declares the tools that the LLM can choose # to run. This section has three tools - two actions and # one transition. actions: send_verification_code: @actions.send_verification_code with email=@variables.member_email with member_number=@variables.member_number set @variables.verification_code=@outputs.verification_code validate_verification_code: @actions.validate_verification_code available when @variables.verification_code != None with verification_code=@variables.user_verification_code set @variables.verified=@outputs.verification go_to_order_management: @utils.transition to @subagent.Order_Management available when @variables.verified == True # This section defines the actions available to this subagent. Actions are # only valid within the subagent in which they are defined. actions: send_verification_code: description: "Send a verification code to the member and verify confirmation." inputs: email: string member_number: string outputs: verification_code: string member_name: string target: "flow://Get_Verification_Code" validate_verification_code: description: "validate the verification code" inputs: verification_code: string outputs: verification: boolean description: "always validate and return True" target: "flow://validate_Verification_Code" subagent Order_Management: description: "Handles order lookup, order updates, and summaries including status, date, location, items, and driver." reasoning: instructions: -> if @variables.order_summary == "": run @actions.lookup_current_order with member_email=@variables.member_email set @variables.order_summary=@outputs.order_summary | Refer to the user by name {!@variables.member_name}. Show their current order summary: {!@variables.order_summary} when conversation starts or if requested. If they want past order info, ask for Order ID and use {!@actions.lookup_order}. actions: # The ... indicates that the LLM can use reasoning to select the # information from the customer's conversation, then input # the information into the correct input variables lookup_order: @actions.lookup_order with query = ... # Store the action's output into variables set @variables.order_summary=@outputs.order_summary set @variables.order_id=@outputs.order_id lookup_current_order: @actions.lookup_current_order with member_email=@variables.member_email set @variables.order_summary=@outputs.order_summary set @variables.order_id=@outputs.order_id actions: lookup_order: description: "Retrieve order details." inputs: query: string outputs: order_summary: string order_id: string target: "flow://Get_Past_Order" lookup_current_order: description: "Retrieve current order details." inputs: member_email: string outputs: order_summary: string order_id: string target: "flow://Get_Current_Order" # End of customer support script ``` ::::: :::::tab Build the agent with clicks in Agentforce Builder's Canvas view, which summarizes Agent Script into easily understandable blocks. For full details on the features used here, see [Building Agents in Canvas View](https://help.salesforce.com/s/articleView?id=ai.agent_canvas.htm&type=5). ### Canvas Step 1: Scaffold the Agent [Create an agent](https://help.salesforce.com/s/articleView?id=ai.agent_setup_create.htm&type=5) in Agentforce Builder. In the setup flow, set the agent's name, running user, description, and tone — the foundation that the agent's instructions and welcome message build on. When you finish, Agentforce Builder opens your new agent in Canvas view. ### Canvas Step 2: Define the Variables Open the Variables panel and create the variables that the agent uses to remember information across the conversation. For each one, set a name, a data type, and an optional default value: - Identity: `member_name`, `member_email`, `member_number`, `verification_code`, `user_verification_code`, and a `verified` boolean (default False). - Orders: `order_id` and an `order_summary` string (default empty). The `verified` boolean and `order_summary` string are the variables that later gate which subagents and actions the agent can use. See [Manage Variables](https://help.salesforce.com/s/articleView?id=ai.agent_builder_variables.htm&type=5). ### Canvas Step 3: Build the Router The router is your start subagent — the agent's entry point on every customer message. In _actions available for reasoning_, add two transition utilities: one to the Identity subagent, one to Order Management. Use a filter (Make this action available when:) so the transition to Identity is available only when `verified` equals False, and the transition to Order Management only when `verified` equals True. This ensures customers verify their identity before they can look up orders. ![A transition utility in a subagent's actions available for reasoning in Canvas view](https://developer.salesforce.com/media/agent-script/canvas/agent_canvas_utility.png '{"class": "image-md image-framed"}') ### Canvas Step 4: Build the Identity Subagent Add a subagent named **Identity** to verify the customer before any order data is exposed. Add the `send_verification_code` and `validate_verification_code` actions (both backed by flows) to _actions available for reasoning_. In the reasoning instructions, use the inline action shortcuts (`/`) to run the send action and store its outputs in variables, and reference the actions as resources (`@`) so the agent validates the code the customer enters. Add a transition to Order Management, available only when `verified` equals True. ![The inline actions shortcut menu, opened with the slash key in Canvas view reasoning instructions](https://developer.salesforce.com/media/agent-script/canvas/agent_canvas_inline_actions.png '{"class": "image-md image-framed"}') ### Canvas Step 5: Build the Order Management Subagent Add a subagent named **Order Management** to look up order details. Add the `lookup_current_order` and `lookup_order` actions. In the reasoning instructions, use a conditional (`/`) so that when `order_summary` is empty, the agent runs `lookup_current_order` and stores the result in the `order_summary` variable. Reference `member_name` and `order_summary` as resources (`@`) to personalize the response. Customers can also look up a past order by providing an Order ID. ![Running the lookup_current_order action inside a conditional instruction in Canvas view](https://developer.salesforce.com/media/agent-script/canvas/agent_canvas_run_action.png '{"class": "image-md image-framed"}') ### Canvas Step 6: Preview and Test In Canvas view, select **Preview** and start a conversation, such as _I need help with my order_. Confirm that the agent asks you to verify your identity first, and that order details return correctly after verification. ::::: :::::: # Agentforce Examples This section provides example Agentforce implementations to help you get started building and using agents. Each example explains the main concepts it demonstrates and gives you what you need to build it yourself. The **Headless Instructions** column identifies examples with guidance on how to build and deploy using an AI coding agent. The multi-surface examples show you how to complete the steps using Headless, Canvas (Salesforce UI), and sometimes Agent Script by choosing the tab for your preferred method. ## End-to-End Agents Build and deploy a complete Agentforce solution from start to finish. | Example | Description | Headless Instructions | | ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | | [Build the Palonia Resort Demo with a Coding Agent](https://developer.salesforce.com/docs/ai/agentforce/guide/headless-example-org-build.md) | Use an AI coding assistant to build and deploy a complete solution — custom objects, sample data, a flow, a Lightning web component, a prompt template, and a service agent — to your org. | Yes | | [Customer Support Agent](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-examples-customer-support.md) | A support agent that verifies a customer's identity and looks up their orders — built three ways: headlessly with an AI coding agent, with code in Agent Script, or with clicks in Canvas. | Yes | | [Build and Deploy an Enhanced Chat Agent](https://developer.salesforce.com/docs/ai/headless/headless-examples-enhanced-chat-agent.md) | Build a chat agent, test and activate it, and deploy it to an Enhanced Chat v2 channel. | Yes | | [Ground an Agent with Agentforce Data Libraries](https://developer.salesforce.com/docs/ai/headless/headless-examples-agent-adl.md) | Build an agent, ground it with an Agentforce data library, test, and activate it. | Yes | | [Optimize an Agent by Analyzing Production Data](https://developer.salesforce.com/docs/ai/headless/headless-examples-agent-optimize.md) | Analyze production data to identify suboptimal agent responses. Your AI assistant identifies root causes, turns them into durable test cases, and suggests fixes, which you validate against a full test suite in your testing environment, such as a sandbox, before promoting to production. | Yes | | [Collect Customer Information to Create a Record](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-lead-gather.md) | An agent that collects required details across multiple turns, then creates a record through a flow — with safeguards against dropped values, duplicate records, and false confirmations. | No | ## Agent Script Techniques Learn specific Agent Script techniques through focused, code-first examples. | Example | Description | | ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | | [Enforce Subagent Sequencing With Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-examples-multi-turn.md) | A step-based interview agent that enforces question order while handling natural conversation. | | [Agent Script Patterns](https://developer.salesforce.com/docs/ai/agentforce/agent-script/patterns/ascript-patterns.md) | Reusable patterns for common Agent Script use cases and workflows. | | [Agent Script Recipes](https://developer.salesforce.com/sample-apps/agent-script-recipes) | Sample implementations that demonstrate Agent Script features and techniques. | ## Extend Your Agent with Data and Actions Ground your agent in your own knowledge and add custom logic that the standard actions don't cover. | Example | Description | Headless Instructions | | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | --------------------- | | [Ground an Agent with an Agentforce Data Library](https://developer.salesforce.com/docs/ai/headless/headless-examples-agent-adl.md) | Build an agent, ground it with an Agentforce data library, test, and activate it. | Yes | | [Demystify Jargon with Knowledge](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-example-rag-jargon.md) | Ensure that your grounded agent understands your organization's evolving jargon without having to update your information sources. | No | | [Custom Apex Action for Complex Queries](https://developer.salesforce.com/docs/ai/agentforce/guide/apex-examples-custom-action.md) | A custom action built in Apex to search product inventory. | No | ## Related Topics - [Agent Script Patterns](https://developer.salesforce.com/docs/ai/agentforce/agent-script/patterns/ascript-patterns.md) - [Agent Script Reference](https://developer.salesforce.com/docs/ai/agentforce/agent-script/reference/ascript-reference.md) # Agentforce Metadata Types (v67 and Earlier) Manage actions and customize the planner service using the [Metadata API](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_intro.htm). **important:** Agent metadata changed in v68. To learn more, see [Move an Agent to a New Org](/docs/ai/agentforce/guide/agent-dx-deploy-metadata.html). ![Agent metadata hierarchy](https://developer.salesforce.com/docs/media/bot-agent-metadata.png '{"class": "image-md"}') ## Metadata Types - [AiAuthoringBundle](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_aiauthoringbundle.htm): Represents an AI authoring bundle, which contains the blueprint of an agent. For example, an AI authoring bundle for an Agentforce agent contains: - an [Agent Script](/docs/ai/agentforce/guide/agent-script.html) file stored in `.agent` - the Metadata API XML, stored in `.bundle-meta.xml` To commit an agent version, the `target` field must specify the `developerName` for the [Bot](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_bot.htm) and [BotVersion](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_botversion.htm) components, separated by a period: `{Bot}.{BotVersion}`. For example, `Agentforce_Service_Agent.v2`. These two components tie the AI authoring bundle to a specific agent and a specific agent version. - [Bot](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_bot.htm): The top-level representation of an [Einstein Bot](https://help.salesforce.com/s/articleView?id=service.bots_service_whats_a_bot.htm&type=5) or an [Agentforce Agent](https://help.salesforce.com/s/articleView?id=ai.copilot_overview.htm&type=5). - `localMlDomain.name`: Agent name. - `type`: Agent type. - `description`: Agent description. - [`ConversationContextVariable`](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_bot.htm#ConversationContextVariable): A context variable local to the current bot or agent version. - [BotVersion](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_botversion.htm): A BotVersion represents the configuration for a specific bot or agent version. A single Einstein Bot or Agentforce Agent can have many versions, but only one version can be active. - [ConversationVariable](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_botversion.htm#ConversationVariable): A container that stores a specific piece of data collected from the customer. You can use variables within actions as both inputs and outputs. - [GenAiFunction](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_genaifunction.htm): Represents an action that can be added to agents. Action input and output variables are located in `schema.json` for each action's input and output folders, or in `schema.json` in the `localActions` folder of `genAIPlannerBundle`. - [GenAiPlannerBundle](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_genaiplannerbundle.htm) represents a planner for an agent or agent template. It’s a container for all the subagents and actions used to interact with a large language model (LLM). An agent has a single GenAiPlannerBundle component. A `GenAIPlannerBundle` file contains the Agentforce Builder Subagent Map for a specific agent. - `GenAiPluginInstructionDef`: Subagent instructions. - [GenAiPlugin](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_genaiplugin.htm): Represents a subagent, which is a category of actions related to a particular job to be done by the agent. An agent can have multiple GenAiPlugin components. - `developerName`: Subagent API name. ## See Also - [Agentforce DX](/docs/ai/agentforce/guide/agent-dx.html) for instructions on how to manage agents using pro-code tools. - [Define Agent Metadata (v67 and Earlier)](/docs/ai/agentforce/guide/agent-dx-api-v67-earlier.html) for instructions on how to use Salesforce DX and agent metadata to move your agent to a new org # Agentforce Metadata Types (v68 and Later) To manage agents, agent actions, and subagents, use the [Metadata API](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_intro.htm). **important:** Agent metadata changed in v68. To learn more, see [Move an Agent to a New Org](/docs/ai/agentforce/guide/agent-dx-deploy-metadata.html). ![Agent metadata hierarchy](https://developer.salesforce.com/docs/media/bot-agent-metadata68.png '{"class": "image-lg"}') ## Metadata Types - [AiAuthoringBundle](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_aiauthoringbundle.htm): Represents an AI authoring bundle, which contains the blueprint of an agent. For example, an AI authoring bundle for an Agentforce agent contains: - An [Agent Script](/docs/ai/agentforce/guide/agent-script.html) file, stored in `.agent` - A Metadata API XML file, stored in `.bundle-meta.xml` - [AiAgentDefinition](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_AiAgentDefinition.htm): Represents the definition of an Agentforce agent, including its type, context variables, and conversation settings. - [AiAgentDefinitionVersion](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_AiAgentDefinitionVersion.htm): Represents a version of an Agentforce agent definition, including its dialogs, conversation variables, planner configuration, and behavior settings. - [GenAiFunction](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_genaifunction.htm): Represents an action that you can add to agents. - [GenAiPlugin](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_genaiplugin.htm): Represents an agent's subagent. ## Metadata Types No Longer Used in Agentforce Agents In v68 and later releases, these metadata types are no longer used to represent Agentforce agents: - [Bot](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_bot.htm) and [BotVersion](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_botversion.htm): Used only by Einstein Bots, not by Agentforce agents. - [GenAiPlannerBundle](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_genaiplannerbundle.htm): Doesn't exist in v68 and later releases. ## See Also - [Agentforce DX](/docs/ai/agentforce/guide/agent-dx.html): Manage agents by using pro-code tools. - [Move an Agent to a New Org](/docs/ai/agentforce/guide/agent-dx-deploy-metadata.html): Use Salesforce DX and agent metadata to move your agent to a new org. # Agentforce Mobile SDK Developer Guide The Agentforce Mobile SDK empowers you to integrate Salesforce's feature-rich, trusted AI platform directly with your iOS, Android, and React Native mobile applications. By leveraging the Agentforce Mobile SDK, you can deliver cutting-edge, intelligent, and conversational AI experiences to your mobile users, enhancing engagement and providing seamless access to information and actions. ## Getting Started - [Overview](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-overview.md) - Overview and key concepts - [Before You Begin](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-before-you-begin.md) - Prerequisites and org setup ## Choose Your Platform ### iOS Development - [Quick Start](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/ios/agentforce-mobile-sdk-ios-quick-start.md) - Get running in 15 minutes - [Requirements](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/ios/agentforce-mobile-sdk-ios-requirements.md) - System requirements and setup - [Install the SDK](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/ios/agentforce-mobile-sdk-ios-install.md) - Dependency installation - [Integration Guide](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/ios/agentforce-mobile-sdk-ios-integration.md) - Complete implementation ### Android Development - [Quick Start](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/android/agentforce-mobile-sdk-android-quick-start.md) - Get running in 15 minutes - [Requirements](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/android/agentforce-mobile-sdk-android-requirements.md) - System requirements and setup - [Install the SDK](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/android/agentforce-mobile-sdk-android-install.md) - Dependency installation - [Integration Guide](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/android/agentforce-mobile-sdk-android-integration.md) - Complete implementation ### React Native Development - [Quick Start](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/react-native/agentforce-mobile-sdk-react-native-quick-start.md) - Get running in 15 minutes - [Requirements](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/react-native/agentforce-mobile-sdk-react-native-requirements.md) - System requirements and setup - [Install the SDK](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/react-native/agentforce-mobile-sdk-react-native-install.md) - Dependency installation - [Integration Guide](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/react-native/agentforce-mobile-sdk-react-native-integration.md) - Complete implementation ## Platform Support The Agentforce Mobile SDK supports iOS, Android, and React Native platforms with feature parity. - **iOS**: Requires iOS 17+ with SwiftUI support - **Android**: Requires Android API level 29+ with Jetpack Compose support - **React Native**: Requires React Native 0.72+, iOS 17+, Android API level 29+ ## Release Notes - [Release Notes](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-release-notes.md) - Latest updates and changes # Agentforce Mobile SDK Reference Overview Technical reference for the Agentforce Mobile SDK APIs and components across iOS and Android platforms. ## Platform Support | Platform | UI Framework | Min Version | Distribution | | -------- | --------------- | ----------- | ------------ | | iOS | SwiftUI | iOS 17+ | CocoaPods | | Android | Jetpack Compose | API 29+ | AAR | ## Core Components The Agentforce Mobile SDK includes the following core components across both platforms: ### Primary Classes | Class | iOS | Android | Description | | ------------------------------------------------------------ | --- | ------- | -------------------------------- | | [AgentforceClient](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ios/agentforce-client-ios.md) | ✅ | ✅ | SDK entry point and orchestrator | | [AgentforceConversation](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ios/agentforce-conversation-ios.md) | ✅ | ✅ | Conversation session management | ### UI Components #### iOS Components | Component | Description | | --------------------------------------------------------------- | -------------------------------------------- | | [AgentforceChatView](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ios/agentforce-chat-view-ios.md) | Full conversational interface | | [AgentforceCard](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ios/agentforce-card-ios.md) | Compact conversation summary | | [AgentforceLauncher](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ios/agentforce-launcher-ios.md) | Floating launcher interface | | [ConversationUIContainer](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ios/conversation-ui-container-ios.md) | Container view for embedding conversation UI | #### Android Components | Component | Description | | -------------------------------------------------------------- | ----------------------------- | | [AgentforceComponent](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/android/agentforce-component-android.md) | Base UI component system | | [ChatResponseButton](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/android/chat-response-button-android.md) | Interactive response elements | | [RecordSelector](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/android/record-selector-android.md) | Salesforce record selection | ### Services & Protocols #### iOS Protocols | Protocol | Description | | --------------------------------------------------------------- | --------------------------- | | [AgentConversation](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ios/agent-conversation-ios.md) | Core conversation interface | | [AgentforceDataProviding](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ios/agentforce-data-providing-ios.md) | Data access abstraction | #### Android Services | Service | Description | | ---------------------------------------------------------- | ----------------------------- | | [AgentforceAPI](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/android/agentforce-api-android.md) | Network service layer | | [AgentforceService](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/android/agentforce-service-android.md) | Backend integration interface | | [BotsAPI](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/android/bots-api-android.md) | Conversation API client | ### Enumerations | Enumeration | iOS | Android | Description | | ----------------------------------------------------------------------- | --- | ------- | ----------------------------- | | [AgentforceConversationState](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ios/agentforce-conversation-state-ios.md) | ✅ | ✅ | Conversation lifecycle states | | [AgentforceAccessMode](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ios/agentforce-access-mode-ios.md) | ✅ | ✅ | Permission and context modes | ### Error Handling | Component | iOS | Android | Description | | -------------------------------------------------------------------------- | --- | ------- | ------------------------------- | | [AgentforceSDKError](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ios/agentforce-sdk-error-ios.md) | ✅ | ✅ | SDK error taxonomy | | [AgentforceDataProviderErrors](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ios/agentforce-data-provider-errors-ios.md) | ✅ | ❌ | Data provider errors (iOS only) | ## Platform-Specific Development ### iOS Development - [iOS Architecture Integration](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ios/architecture-integration-ios.md) - [iOS UI Components](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ios/ui-components-ios.md) - [iOS Development](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ios/development-ios.md) - [iOS Typography](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ios/typography-and-fonts-ios.md) ### Android Development - [Android Architecture Integration](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/android/architecture-integration-android.md) - [Android UI Components](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/android/ui-components-android.md) - [Android Development](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/android/development-android.md) - [Android Typography](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/android/typography-and-fonts-android.md) ## Related Documentation - [Agentforce Mobile SDK Developer Guide](/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-overview.html) - Implementation guides and patterns - [iOS Integration Guidelines](/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-ios.html) - iOS platform setup - [Android Integration Guidelines](/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-android.html) - Android platform setup # Agentforce Plugins and Skills Plugins and skills are reusable packages that extend AI coding tools (like Agentforce Vibes, Claude Code, and other coding agents) with Salesforce- and Agentforce-specific capabilities. Use them so your coding agent already knows how to build, deploy, and debug Agentforce work without you having to re-explain context every session. ## What Are Plugins and Skills? - **Skills** are bundles of instructions, examples, and grounding content that teach an AI coding tool how to perform a specific kind of Salesforce work, such as building an Agentforce agent with Agent Script or deploying metadata to an org. Skills use tools, such as Salesforce CLI and various Salesforce APIs, under the covers. You don't have to remember the specifics of each CLI command or API call because the skills know which tools to invoke at the appropriate time. - **Plugins** package related capabilities (skills, MCP servers, and tools) together so an AI coding tool can pick them up in one step. ## Where to Find Skills and Plugins Salesforce-built skills and plugins live in open repos that you can browse, install, and contribute to: - **[Salesforce Skills Library](https://github.com/forcedotcom/sf-skills)** — Skills covering broader Salesforce platform work. The skills library include skills focused on the Agentforce Development Lifecycle (ADLC) and broader Salesforce platform work. Popular ADLC skills include `agentforce-generate`, `agentforce-observe`, and `agentforce-test` for creating agent script, analyzing session trace data, and running test suites. The Salesforce Skills Library are pre-installed for Agentforce Vibes. - **[salesforce-development Plugin on Claude Code](https://claude.com/plugins/salesforce-development)** — One-step installation of the `salesforce-development` plugin for use in Claude Code, so your coding agent can build, modify, debug, and deploy agents with Agent Script without extra setup. To install, run `claude plugin install salesforce-development@claude-plugins-official`. This plugin is equivalent to the Salesforce Skills Library that's pre-installed for Agentforce Vibes. See [Salesforce Development Plugin for Claude Code](https://developer.salesforce.com/docs/platform/salesforce-skills-plugins/guide/salesforce-development-overview.html). ## See Also - [Agentic Development](https://developer.salesforce.com/docs/ai/headless/headless.md) - [Headless Development Tools](https://developer.salesforce.com/docs/ai/headless/headless-tools.md) - [Download Agent Script Documentation](https://developer.salesforce.com/docs/ai/agentforce/agent-script/ascript-download-documentation.md) - [Agentforce Vibes Extension](https://developer.salesforce.com/docs/ai/vs-code-extension.md) - [MCP Solutions](https://developer.salesforce.com/docs/ai/mcp.md) # Agentforce Service Errors This reference contains errors from Agentforce platform services, organized by service and error code. Documentation for each error includes possible causes, troubleshooting steps, and if necessary, when to reach out to Salesforce Customer Support and what information to provide. | Service | Description | | -------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Agent Service Reasoner Errors](https://developer.salesforce.com/docs/ai/agentforce/guide/error-ref-agent-svc-reasoner.md) | The Agent Service Reasoner manages agent conversations on two surfaces: the multi-agent orchestration layer, where connected subagents collaborate to complete complex tasks, and the single-agent reasoning endpoint, where individual agents process requests from users and calling applications. Errors from this service typically indicate that a request was malformed or missing required context, that the requested agent or session couldn't be found, that the caller lacked permission, or that a language model call timed out, was rate limited, or encountered a service-side failure. | | [Agentforce Data Library Service Errors](https://developer.salesforce.com/docs/ai/agentforce/guide/error-ref-agentforce-data-library.md) | The Agentforce Data Library service manages data libraries, sources, retrievers, and file uploads for use in Agentforce agents. Errors from this service typically indicate that a requested resource wasn't found, that a permission or prerequisite is missing, that a request field failed validation, or that a provisioning operation encountered a temporary failure. | | [Authentication Service Errors](https://developer.salesforce.com/docs/ai/agentforce/guide/error-ref-auth-service.md) | The Agentforce authentication service manages org provisioning and the credentials that allow Agentforce and Einstein AI features to operate. Errors from this service typically indicate that an org couldn't be provisioned, that authentication credentials couldn't be validated, or that a platform dependency the service relies on was temporarily unavailable. | | [Bring Your Own Node Service Errors](https://developer.salesforce.com/docs/ai/agentforce/guide/error-ref-icr-byon.md) | The Bring Your Own Node (BYON) service runs custom code nodes within Agentforce agent workflows. When your agent runs, the reasoning engine walks a graph of steps to fulfill a request. Each node in that graph represents a discrete operation. The reasoning engine determines which node to call, assembles the inputs, and calls your code to execute it. Errors from this service typically indicate that the requested node wasn't found, that the request payload failed validation, that the caller lacked permission to execute the node, or that the execution timed out or was cancelled before completing. | | [Einstein Compute Service Errors](https://developer.salesforce.com/docs/ai/agentforce/guide/error-ref-ccp-service.md) | The Einstein Compute service schedules and runs AI model training and data processing jobs that power Agentforce and other generative AI features. Errors from this service typically indicate that a job request was invalid or referenced a resource that doesn't exist, that the platform's compute infrastructure was temporarily unavailable or at capacity, or that an internal dependency encountered an unexpected failure. | | [General Agentforce Service Errors](https://developer.salesforce.com/docs/ai/agentforce/guide/error-ref-common.md) | These error codes can be returned by any Agentforce service. They represent platform-level conditions that apply across services, such as rate limiting, temporary unavailability, and unexpected system failures. | | [Interactive Data Science Service Errors](https://developer.salesforce.com/docs/ai/agentforce/guide/error-ref-interactive-data-science.md) | The Interactive Data Science service is the backend infrastructure for Model Studio, where admins and data scientists create projects, connect data sources, and deploy custom models into Agentforce and Einstein AI features. Errors from this service typically indicate that a project request was invalid or referenced a resource that doesn't exist, that the org isn't enabled for the requested capability, or that a platform dependency the service relies on was temporarily unavailable. | | [Language Detection Service Errors](https://developer.salesforce.com/docs/ai/agentforce/guide/error-ref-language-detection.md) | The language detection service identifies the language of text submitted through Agentforce and Einstein AI features. Errors from this service typically indicate that the input text was too short or the wrong type, that required parameters were missing, or that the pipeline configuration connecting language detection to other steps was incorrect. | | [ML Lake Service Errors](https://developer.salesforce.com/docs/ai/agentforce/guide/error-ref-mllake.md) | The ML Lake service manages data storage access for Einstein AI pipeline jobs. Errors from this service typically indicate that the request or org identifier was invalid, that credentials couldn't be issued or aren't authorized, or that the service was temporarily unavailable. | | [Model Builder Errors](https://developer.salesforce.com/docs/ai/agentforce/guide/error-ref-edc-model-builder.md) | The Model Builder service trains predictive AI models on your Data 360 data. Errors from this service typically indicate that a training job request was invalid or missing required parameters, that a job or model artifact couldn't be found, or that a platform dependency the service relies on was temporarily unavailable. | | [Prediction Service Errors](https://developer.salesforce.com/docs/ai/agentforce/guide/error-ref-prediction.md) | The prediction service routes AI inference requests to the appropriate models. Errors from this service typically indicate that a request failed schema validation or violated a business rule, that the requested application type or model version isn't supported in the current environment, that authentication failed, or that a required model configuration couldn't be found on the platform. | # Agentforce Tooling Objects Manage actions and customize the planner service using the [Tooling API](https://developer.salesforce.com/docs/atlas.en-us.api_tooling.meta/api_tooling/intro_api_tooling.htm). - [GenAiFunctionDefinition](https://developer.salesforce.com/docs/atlas.en-us.api_tooling.meta/api_tooling/tooling_api_objects_genaifunctiondefinition.htm): Represents an action that can be added to agents. - [GenAiPlannerDefinition](https://developer.salesforce.com/docs/atlas.en-us.api_tooling.meta/api_tooling/tooling_api_objects_genaiplannerdefinition.htm): Represents a planner that uses an LLM and a reasoning strategy to break down a task into smaller parts, find the best actions for each part, and invoke them. # Agentforce Vibes Extension The [Agentforce Vibes extension](https://developer.salesforce.com/docs/platform/einstein-for-devs/guide/einstein-overview.html) is an AI-powered developer tool that's available as an easy-to-install Visual Studio Code extension. The extension is available in the [VS Code](https://marketplace.visualstudio.com/items?itemName=salesforce.salesforcedx-einstein-gpt) and [Open VSX](https://open-vsx.org/extension/salesforce/salesforcedx-einstein-gpt) marketplaces as a part of the [Salesforce Extension Pack](https://marketplace.visualstudio.com/items?itemName=salesforce.salesforcedx-vscode), [Salesforce Extension Pack (Expanded)](https://marketplace.visualstudio.com/items?itemName=salesforce.salesforcedx-vscode-expanded), and in the Agentforce Vibes IDE. ![Agentforce Vibes](https://developer.salesforce.com/docs/media/vibes.webp) To learn more, see the [Agentforce Vibes Extension Developer Guide](https://developer.salesforce.com/docs/platform/einstein-for-devs/guide/einstein-overview.html). ## See Also - [Headless Development Tools](https://developer.salesforce.com/docs/ai/agentforce/guide/headless/headless-tools.md) # AgentforceAccessMode `enum class AgentforceAccessMode` Access modes that define the level of permissions and UI context for record operations on Android. ## Overview Access modes that define the level of permissions and UI context for record operations. These modes work in conjunction with Salesforce field-level security and object permissions to provide appropriate access levels for different user scenarios. ## Declaration ```kotlin enum class AgentforceAccessMode ``` ## Properties | Property | Type | Description | | --------- | ---- | -------------------------------------------------------- | | VIEW | enum | Read-only access mode | | EDIT | enum | Full edit access mode | | CREATE | enum | Creation mode for new records | | REFERENCE | enum | Reference mode for displaying related record information | ## Methods | Method | Signature | Description | | ------ | --------- | ---------------------- | | N/A | N/A | Enumeration cases only | ## Usage Examples ### Basic Usage ```kotlin // Example usage in data access val accessMode: AgentforceAccessMode = AgentforceAccessMode.VIEW // Switch based on user permissions when (accessMode) { AgentforceAccessMode.VIEW -> { // Show read-only interface } AgentforceAccessMode.EDIT -> { // Show editable interface } AgentforceAccessMode.CREATE -> { // Show creation interface } AgentforceAccessMode.REFERENCE -> { // Show reference information } } ``` ### Security Considerations Access modes work in conjunction with Salesforce field-level security and object permissions: - Mode permissions are enforced at the SDK level - Salesforce permissions still apply - Access mode cannot grant permissions not available to the user - Use appropriate modes based on user capabilities and intent ## Related Components - [AgentforceConversation](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-conversation-android.md) - Conversation management - [AgentforceService](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-service-android.md) - Backend integration # AgentforceAccessMode ## Overview Access modes that define the level of permissions and UI context for record operations. These modes correspond to Salesforce's access control and determine what actions are available and how the UI should be configured for record interaction. ## Declaration ```swift enum AgentforceAccessMode ``` ## Properties | Property | Type | Description | | -------- | ---- | ------------------------------------------ | | View | case | View mode - for read-only record display | | Edit | case | Edit mode - for modifying existing records | | Create | case | Create mode - for adding new records | ## Methods | Method | Signature | Description | | ------ | ----------------------- | ------------------------------------------- | | init | init?(rawValue: String) | Creates an instance from a raw string value | # AgentforceAPI `class AgentforceAPI` Network service layer providing comprehensive API access to Agentforce backend services and conversation management. ## Constructor ```kotlin class AgentforceAPI( network: Network, domain: String? = null, sse: AgentforceServerSentEvents, credentialProvider: AgentforceAuthCredentialProvider, instrumentationHandler: AgentforceInstrumentationHandler? = null, configurationLocale: Locale? = null, agentforceLogger: Logger? = null, agentId: String? = null, ioDispatcher: CoroutineDispatcher = Dispatchers.IO ) ``` ## Parameters | Parameter | Type | Description | | ---------------------- | --------------------------------- | ---------------------------------------------- | | network | Network | Network interface for HTTP operations | | domain | String? | Optional Salesforce domain override | | sse | AgentforceServerSentEvents | Server-Sent Events implementation | | credentialProvider | AgentforceAuthCredentialProvider | Authentication credential management | | instrumentationHandler | AgentforceInstrumentationHandler? | Analytics and performance monitoring | | configurationLocale | Locale? | Localization configuration | | agentforceLogger | Logger? | Logging interface implementation | | agentId | String? | Default agent identifier | | ioDispatcher | CoroutineDispatcher | Coroutine dispatcher for background operations | ## Overview `AgentforceAPI` serves as the primary interface for network communication with Agentforce backend services. It handles authentication, request/response processing, real-time event streaming, and error management in a coroutine-friendly architecture. ## Core Capabilities Essential capabilities of the AgentforceAPI for network communication and conversation management. ### Conversation Management - Start and manage agent conversation sessions - Send user messages and receive agent responses - Handle conversation state transitions - Support for conversation persistence and restoration ### Real-Time Communication - Server-Sent Events (SSE) for live message streaming - Connection management and automatic reconnection - Event filtering and processing - WebSocket fallback support ### Authentication Integration - OAuth 2.0 token management - Automatic token refresh - Org JWT support for service accounts - Secure credential storage and retrieval ## Usage Patterns Common patterns for initializing and using the AgentforceAPI. ### Basic API Setup ```kotlin val networkProvider = MyNetworkImplementation() val credentialProvider = MyCredentialProvider() val sseService = AgentforceServerSentEvents() val logger = MyLoggerImplementation() val agentforceAPI = AgentforceAPI( network = networkProvider, domain = "https://my-org.salesforce.com", sse = sseService, credentialProvider = credentialProvider, agentforceLogger = logger, agentId = "default-agent-id" ) ``` ### Starting a Conversation ```kotlin class ConversationRepository(private val api: AgentforceAPI) { suspend fun startConversation( agentId: String, sessionId: String? = null ): Result { return try { val response = api.createConversation( agentId = agentId, sessionId = sessionId ) Result.success(response) } catch (e: Exception) { Result.failure(e) } } } ``` ### Sending Messages ```kotlin suspend fun sendMessage( conversationId: String, message: String, metadata: Map = emptyMap() ): Result { return try { val messageRequest = MessageRequest( text = message, conversationId = conversationId, metadata = metadata ) val response = api.sendMessage(messageRequest) Result.success(response) } catch (e: Exception) { Result.failure(e) } } ``` ### Real-Time Event Streaming ```kotlin class ConversationEventHandler(private val api: AgentforceAPI) { fun observeConversationEvents(conversationId: String): Flow { return api.subscribeToConversationEvents(conversationId) .catch { exception -> // Handle connection errors handleStreamingError(exception) } .filterIsInstance() } private suspend fun handleStreamingError(exception: Throwable) { when (exception) { is NetworkException -> { // Attempt reconnection retryConnection() } is AuthenticationException -> { // Refresh credentials refreshAuthentication() } } } } ``` ## Error Handling Comprehensive error handling patterns for network and API failures. ### Network Error Management ```kotlin class ApiErrorHandler { suspend fun safeApiCall( apiCall: suspend () -> T ): Result { return try { Result.success(apiCall()) } catch (e: HttpException) { when (e.code()) { 401 -> Result.failure(AuthenticationException("Token expired")) 403 -> Result.failure(AuthorizationException("Insufficient permissions")) 429 -> Result.failure(RateLimitException("Too many requests")) else -> Result.failure(NetworkException("API call failed: ${e.message}")) } } catch (e: IOException) { Result.failure(NetworkException("Network connection failed")) } } } ``` ### Retry Logic ```kotlin class RetryableApiClient(private val api: AgentforceAPI) { suspend fun executeWithRetry( maxRetries: Int = 3, backoffMs: Long = 1000, operation: suspend () -> T ): T { repeat(maxRetries) { attempt -> try { return operation() } catch (e: Exception) { if (attempt == maxRetries - 1) throw e val delayMs = backoffMs * (2.0.pow(attempt.toDouble())).toLong() delay(delayMs) } } throw IllegalStateException("Retry logic failed") } } ``` ## Authentication Integration Integration patterns for authentication and credential management. ### Credential Provider Implementation ```kotlin class MyCredentialProvider : AgentforceAuthCredentialProvider { override suspend fun getAuthCredential(): AgentforceAuthCredential { return when (val authType = determineAuthType()) { AuthType.OAUTH -> { AgentforceAuthCredential.OAuth( authToken = getOAuthToken(), orgId = getOrgId(), userId = getUserId() ) } AuthType.ORG_JWT -> { AgentforceAuthCredential.OrgJWT( orgJWT = getOrgJWT() ) } } } override suspend fun refreshCredential(): AgentforceAuthCredential { // Handle token refresh logic return getAuthCredential() } } ``` ### Token Management ```kotlin class TokenManager(private val api: AgentforceAPI) { private var currentToken: String? = null private var tokenExpiry: Long = 0 suspend fun getValidToken(): String { if (isTokenExpired()) { refreshToken() } return currentToken ?: throw AuthenticationException("No valid token") } private fun isTokenExpired(): Boolean { return System.currentTimeMillis() >= tokenExpiry } private suspend fun refreshToken() { val credential = api.credentialProvider.refreshCredential() currentToken = credential.token tokenExpiry = System.currentTimeMillis() + TOKEN_REFRESH_BUFFER } } ``` ## Server-Sent Events Real-time event streaming capabilities for live conversation updates. ### Event Stream Management ```kotlin class ConversationEventStream(private val api: AgentforceAPI) { fun observeEvents(conversationId: String): Flow { return api.sse.connect( endpoint = "/conversations/$conversationId/events", headers = mapOf( "Authorization" to "Bearer ${api.getAuthToken()}", "Accept" to "text/event-stream" ) ).map { sseEvent -> parseAgentforceEvent(sseEvent) } } private fun parseAgentforceEvent(sseEvent: SSEEvent): AgentforceEvent { return when (sseEvent.type) { "message" -> AgentforceMessageEvent.fromJson(sseEvent.data) "typing" -> AgentforceTypingEvent.fromJson(sseEvent.data) "error" -> AgentforceErrorEvent.fromJson(sseEvent.data) else -> AgentforceUnknownEvent(sseEvent.data) } } } ``` ## Instrumentation and Logging Monitoring and logging capabilities for API performance and debugging. ### Performance Monitoring ```kotlin class ApiInstrumentation : AgentforceInstrumentationHandler { override fun onRequestStarted(request: ApiRequest) { recordEvent("api_request_started") { put("endpoint", request.endpoint) put("method", request.method) put("timestamp", System.currentTimeMillis()) } } override fun onRequestCompleted( request: ApiRequest, response: ApiResponse, durationMs: Long ) { recordEvent("api_request_completed") { put("endpoint", request.endpoint) put("status_code", response.statusCode) put("duration_ms", durationMs) put("success", response.isSuccessful) } } override fun onRequestFailed(request: ApiRequest, error: Throwable) { recordEvent("api_request_failed") { put("endpoint", request.endpoint) put("error_type", error::class.simpleName) put("error_message", error.message) } } } ``` ## Dependency Integration Integration patterns for external dependencies and service providers. ### Network Provider Interface ```kotlin interface Network { suspend fun execute(request: NetworkRequest): NetworkResponse suspend fun executeStream(request: StreamRequest): Flow } class MyNetworkProvider : Network { private val httpClient = OkHttpClient.Builder() .addInterceptor(AuthenticationInterceptor()) .addInterceptor(LoggingInterceptor()) .build() override suspend fun execute(request: NetworkRequest): NetworkResponse { // Implement HTTP request execution return executeHttpRequest(request) } override suspend fun executeStream(request: StreamRequest): Flow { // Implement SSE streaming return executeSSERequest(request) } } ``` ## Configuration Options Advanced configuration options for API customization and localization. For detailed configuration examples including locale and dispatcher configuration, see the [Android SDK Developer Guide](/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-android.html#advanced-configuration-patterns). ## See Also - [AgentforceService](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-service-android.md) - High-level service interface - [BotsAPI](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/bots-api-android.md) - Specialized conversation API client - [AgentforceComponent](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/android/agentforce-component-android.md) - UI component system integration # AgentforceAttachment `interface AgentforceAttachment` Agentforce Attachment data classes ## Signature ```kotlin interface AgentforceAttachment ``` ## Properties | Property | Type | Description | | ---------------- | ------------------------------------- | -------------------------------------------- | | `attachmentData` | `AgentforceAttachment.AttachmentData` | Attachment data containing source URI and ID | | `mimeType` | `String?` | MIME type of the attachment | ## Methods | Method | Signature | Description | | ---------------- | --------------------------------------------------------------------- | ------------------------------ | | `attachmentType` | `fun attachmentType(): AgentforceAttachment.AgentforceAttachmentType` | Returns the type of attachment | ## Nested Types ### AttachmentData ```kotlin data class AttachmentData( val sourceUri: Uri? = null, val sourceId: String? = null ) ``` ### AgentforceAttachmentType ```kotlin enum class AgentforceAttachmentType : Enum ``` **Entries:** - `Image` - `PDF` - `SalesforceFile` `Image` and `PDF` are the attachment types supported for multimodal input to the AI agent. `SalesforceFile` covers files relayed through Salesforce outside of that input path, such as files a human agent shares during a conversation handoff. ## Implementations | Class | Description | | ---------------- | ----------------------------------------- | | `Image` | Image attachment implementation | | `PDF` | PDF attachment implementation | | `SalesforceFile` | Salesforce file attachment implementation | ## Related Documentation - [AgentforceMessage](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/android/agentforce-message-android.md) - [AgentforceConversation](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-conversation-android.md) # AgentforceAuthCredentialProvider `interface AgentforceAuthCredentialProvider` ## Signature ```kotlin interface AgentforceAuthCredentialProvider ``` ## Properties | Property | Type | Description | | ------------- | --------- | ---------------------------------------- | | `isGuestUser` | `Boolean` | Returns true if the user is a guest user | ## Methods | Method | Signature | Description | | -------------------- | ----------------------------------------------------- | ------------------------------------------------- | | `getAuthCredentials` | `fun getAuthCredentials(): AgentforceAuthCredentials` | Returns the auth credentials for the current user | ## Related Documentation - [AgentforceAuthCredentials](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-auth-credentials-android.md) - [AgentforceConfiguration](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-configuration-android.md) # AgentforceAuthCredentialProviding ## Overview Protocol that provides authentication credentials for Agentforce service communication. Implement this protocol to supply the SDK with the necessary authentication tokens and credentials required to establish secure connections with Agentforce services. ## Declaration ```swift protocol AgentforceAuthCredentialProviding ``` ## Methods | Method | Signature | Description | | ---------------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `getAuthCredentials` | `func getAuthCredentials() -> AgentforceAuthCredentials` | Returns the current authentication credentials for Agentforce service access. | | `fetchMIAWJWTForPassthrough` | `func fetchMIAWJWTForPassthrough(pathOrUrl:serviceApiURL:esDeveloperName:) async throws -> PassthroughVerification?` | Fetches MIAW JWT from the passthrough endpoint for user verification. This method allows credential providers that have access to SalesforceSDKCore to use RestRequest instead of URLRequest for better authentication handling. | ## Implementation Patterns ```swift class OAuthCredentialProvider: AgentforceAuthCredentialProviding { func getAuthCredentials() -> AgentforceAuthCredentials { // Retrieve OAuth token from your authentication system let token = AuthManager.shared.currentAccessToken let orgId = AuthManager.shared.currentOrgId let userId = AuthManager.shared.currentUserId return .OAuth(authToken: token, orgId: orgId, userId: userId) } func fetchMIAWJWTForPassthrough( pathOrUrl: String, serviceApiURL: String, esDeveloperName: String ) async throws -> PassthroughVerification? { // Implement passthrough JWT fetching if needed // Default implementation throws MIAWJWTFetchNotImplemented throw AgentforceError.MIAWJWTFetchNotImplemented } } ``` ```swift class GuestCredentialProvider: AgentforceAuthCredentialProviding { func getAuthCredentials() -> AgentforceAuthCredentials { return .Guest(url: "https://myorg.salesforce.com") } func fetchMIAWJWTForPassthrough( pathOrUrl: String, serviceApiURL: String, esDeveloperName: String ) async throws -> PassthroughVerification? { throw AgentforceError.MIAWJWTFetchNotImplemented } } ``` # AgentforceAuthCredentials `sealed class AgentforceAuthCredentials` ## Signature ```kotlin sealed class AgentforceAuthCredentials ``` ## Methods | Method | Signature | Description | | ------------ | ---------------------------------------- | ---------------------------------------- | | `getHeaders` | `fun getHeaders(): Map?` | Returns the headers for the current user | ## Nested Types ### OAuth ```kotlin data class OAuth( val authToken: String, val orgId: String, val userId: String ) : AgentforceAuthCredentials() ``` ### OrgJWT ```kotlin data class OrgJWT( val orgJWT: String ) : AgentforceAuthCredentials() ``` ### Guest ```kotlin data class Guest( val url: String ) : AgentforceAuthCredentials() ``` ## Related Documentation - [AgentforceAuthCredentialProvider](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-auth-credential-provider-android.md) - [AgentforceConfiguration](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-configuration-android.md) # AgentforceCard ## Overview A SwiftUI view that displays Agentforce conversation content in a compact, card-style interface. The `AgentforceCard` provides a condensed view of AI conversation content, designed for integration into dashboards, summary screens, or any interface where space is constrained. It intelligently manages content display with expandable/collapsible functionality for longer responses. ## Declaration ```swift @MainActor struct AgentforceCard ``` ## Properties | Property | Type | Description | | -------- | ----------- | --------------------------------- | | `body` | `some View` | The main view content of the card | ## Methods | Method | Signature | Description | | -------------------- | ---------------------- | ------------------------------------ | | View Implementations | `View-Implementations` | Default SwiftUI view implementations | ## Example Usage ```swift // Basic integration in a dashboard VStack { HeaderView() AgentforceCard( viewModel: conversationViewModel, launchChatView: { presentFullConversation() } ) OtherDashboardContent() } // In a scrollable interface ScrollView { LazyVStack { ForEach(cardData) { data in AgentforceCard( viewModel: data.viewModel, launchChatView: { navigateToConversation(data.id) } ) } } } ``` # AgentforceCarousel ## Overview A horizontal scrolling carousel view that displays cards. ## Declaration ```swift @MainActor struct AgentforceCarousel ``` ## Properties | Property | Type | Description | | -------- | ----------- | ------------------------------------- | | `body` | `some View` | The main view content of the carousel | ## Methods | Method | Signature | Description | | -------------------- | ---------------------- | ------------------------------------ | | View Implementations | `View-Implementations` | Default SwiftUI view implementations | # AgentforceChatView ## Overview Type alias providing a more intuitive name for the main chat interface component. `AgentforceChatView` is the primary SwiftUI view for displaying and interacting with Agentforce conversations. It provides a complete chat interface including message history, input controls, voice interaction, and rich content rendering capabilities. ## Declaration ```swift typealias AgentforceChatView = ConversationUIContainer ``` ## Properties | Property | Type | Description | | ---------------- | ----------- | ----------------------------------------------------------- | | `body` | `some View` | The main view content of the chat interface | | `alternateTitle` | `String?` | Optional custom title to display in the conversation header | ## Methods | Method | Signature | Description | | ------------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | `updateSession(session:)` | `func updateSession(session: AgentConversation) throws` | Updates the conversation session with a new session instance | | `sendUtterance(_:)` ⚠️ | `func sendUtterance(_ utterance: String)` ⚠️ | **Deprecated:** Messages should be sent using [AgentforceConversation.sendUtterance](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-conversation-ios.md#sendutterance) | | `resetChat()` ⚠️ | `func resetChat()` ⚠️ | **Deprecated:** The chat should be cleared using [AgentforceConversation.reset](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-conversation-ios.md#reset) | | View Implementations | `View-Implementations` | Default SwiftUI view implementations | # AgentforceClient ```kotlin class AgentforceClient : AgentforceConversationManaging ``` Implementation of AgentforceClient. This will allow to start the Agentforce conversations and presents window. ## Constructors - `AgentforceClient()` ## Properties | Property | Type | Mutability | Description | | -------------------------------- | --------------------------------- | ------------ | -------------------------------------------- | | agentforceInstrumentationHandler | AgentforceInstrumentationHandler? | var | Analytics and performance monitoring handler | | contextManager | AgentforceContextManager? | var | Context manager instance | | conversationService | ConversationService | lateinit var | Conversation service instance | | onboardingManager | AgentforceOnboardingManager | lateinit var | Onboarding manager instance | | pageContext | StateFlow | val | Page context state flow | ## Functions | Function | Signature | Description | | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | | AgentforceCardContainer | `@Composable override fun AgentforceCardContainer(Modifier, AgentforceConversation, AgentforceComponent): Unit` | | | AgentforceConversationContainer | `@Composable open override fun AgentforceConversationContainer(AgentforceConversation, onClick: () -> Unit): Unit` | Draws the Agentforce conversation container with a top bar | | AgentforceConversationContainer | `@Composable open override fun AgentforceConversationContainer(AgentforceConversation, Boolean, onClick: () -> Unit): Unit` | Draws the Agentforce conversation container | | AgentforceLauncherContainer | `@Composable open override fun AgentforceLauncherContainer(AgentforceConversation, onClick: () -> Unit): Unit` | | | AgentforceVoiceContainer | `@Composable fun AgentforceVoiceContainer(AgentforceConversation, onClick: () -> Unit): Unit` | Creates a separate voice interface for real-time voice interaction with visual feedback | | createAgentforceResponseCardManager | `open override fun createAgentforceResponseCardManager(AgentforceConversation, String?): AgentforceResponseCardManager` | Creates a multiturn card manager for the specified conversation | | findAgentforceConversation | `fun findAgentforceConversation(String, String?): AgentforceConversation?` | | | getCurrentContextManager | `fun getCurrentContextManager(): AgentforceContextManager?` | Returns the current context manager instance | | init | `fun init(CoroutineScope?, AgentforceAuthCredentialProvider?, AgentforceMode, Application): Unit` | Initialize the session by providing the required parameters | | startAgentforceConversation | `open override fun startAgentforceConversation(String?, String?): AgentforceConversation` | Start a conversation with the Agentforce assistant | | updatePageContext | `fun updatePageContext(AgentforcePageContext): Unit` | | ## Inherited Functions - clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait # AgentforceClient ## Overview The primary entry point and orchestrator for all Agentforce SDK functionality. It serves as the central coordinator that manages agent conversations, UI component creation, and service dependencies. It implements a comprehensive architecture that handles authentication, networking, theming, and extensibility through provider protocols. ## Declaration ```swift class AgentforceClient ``` ## Methods | Method | Signature | Description | | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | init | init(credentialProvider:mode:viewProvider:themeManager:) | Creates an AgentforceClient with full customization capabilities including view provider overrides | | startAgentforceConversation(forAgentId:sessionId:) | func startAgentforceConversation(forAgentId: String?, sessionId: String?) -> AgentConversation | Initiates a new conversation session with an Agentforce agent | | startAgentforceConversation(forESDeveloperName:) | func startAgentforceConversation(forESDeveloperName: String) -> AgentConversation | Initiates a new conversation session with a service agent using Einstein Service developer name | | getExistingAgentforceConversation | func getExistingAgentforceConversation(forAgentId: String, sessionId: String?) -> AgentConversation? | Gets an existing Agentforce conversation that matches the specified criteria | | createAgentforceChatView | func createAgentforceChatView(conversation:delegate:showTopBar:onContainerClose:) throws -> AgentforceChatView | Creates a fully-configured Agentforce chat interface for interactive dialogue | | createAgentforceCard | func createAgentforceCard(chatView:launchChatView:) -> AgentforceCard | Creates a compact conversation summary card with follow-up interaction capabilities | | createAgentforceLauncher | func createAgentforceLauncher(chatView:launchChatView:) -> AgentforceLauncher | Creates an Agentforce Launcher View | | createAgentforceVoiceView | func createAgentforceVoiceView(conversation:voiceIcon:circleSizeRatio:onContainerClose:) throws -> AgentforceVoiceView | Creates an Agentforce Voice View for real-time voice interaction with visual feedback | ## Usage Patterns ```swift let client = AgentforceClient( credentialProvider: myCredentialProvider, agentforceConfiguration: myConfiguration ) ``` ```swift // 1. Start conversation let conversation = client.startAgentforceConversation(forAgentId: "agent123", sessionId: nil) // 2. Create chat interface let chatView = try client.createAgentforceChatView( conversation: conversation, delegate: myUIDelegate, onContainerClose: { /* handle close */ } ) // 3. Create summary card (optional) let card = client.createAgentforceCard( chatView: chatView, launchChatView: { /* handle launch */ } ) // 4. let voiceView = try client.createAgentforceVoiceView( conversation: conversation, circleSizeRatio: 0.4, onContainerClose: { /* close the voice view and open the associated chat view */ } ) ``` # AgentforceColorPalette ## Overview `AgentforceColorPalette` is the protocol that declares every color token used throughout the Agentforce SDK, providing semantic color tokens for consistent theming across all UI components. It refines `SharedUI.Colors`, which declares the generic foundation tokens shown below. For the full list of all 275 tokens — including the 224 component-specific tokens — see the [Color Token Reference](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-color-token-reference-ios.md). ## Declaration ```swift protocol AgentforceColorPalette: SharedUI.Colors ``` ## Properties (generic tokens) | Property | Type | Description | | --------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------- | | `accent1` | `Color` | Fill color for text and icons on buttons and interactive elements | | `accent2` | `Color` | Fill color for text and icons on buttons and interactive elements | | `accent3` | `Color` | Fill color for text and icons on buttons and interactive elements | | `accent4` | `Color` | Agentforce Specific tokens | | `accent5` | `Color` | Agentforce Specific tokens | | `accentContainer1` | `Color` | Fill color for accent component containers | | `border1` | `Color` | Border color for components that are decorative or divider lines between content | | `border2` | `Color` | Border color for components that are functional or interactive | | `borderDisabled1` | `Color` | Border color for disabled containers | | `borderError1` | `Color` | Border color for error containers | | `borderInverse2` | `Color` | Border color for components that are functional or interactive on a dark background | | `borderSuccess1` | `Color` | Border color for success containers | | `brandBase50` | `Color` | Cosmos foundation color | | `disabledContainer1` | `Color` | Background of disabled component containers for white components | | `disabledContainer2` | `Color` | Background of disabled component containers for dark components | | `error1` | `Color` | Fill color for text and icons displaying an error | | `errorBase50` | `Color` | Cosmos foundation color | | `errorContainer1` | `Color` | Background of error component containers | | `feedbackWarning1` | `Color` | Warning text color | | `feedbackWarningContainer1` | `Color` | Warning container background | | `info1` | `Color` | Information text color | | `infoContainer1` | `Color` | Information container background | | `onAccent1` | `Color` | Text and icon fill color displayed in accent containers | | `onDisabled1` | `Color` | Fill color for text and icons displayed on top of disabledContainer1 | | `onDisabled2` | `Color` | Fill color for text and icons displayed on top of disabledContainer2 | | `onError1` | `Color` | Fill color for text and icons displayed on top of an error container | | `onSuccess1` | `Color` | Fill color for text and icons displayed on top of a success container | | `onSurface1` | `Color` | Lightest text or icon fill | | `onSurface2` | `Color` | Darker text or icon fill | | `onSurface3` | `Color` | Additional text or icon variant | | `successContainer1` | `Color` | Background of success component containers | | `surface1` | `Color` | View background color | | `surface2` | `Color` | View background color | | `surfaceContainer1` | `Color` | Default background color for component containers | | `surfaceContainer2` | `Color` | Darker background color for component containers | | `surfaceContainer3` | `Color` | Darkest background color for component containers | | `backgroundColor` ⚠️ | `Color` | **Deprecated:** This property will be retired in a future release. Switch to a styling hook or use your own custom color. | | `foregroundColor` ⚠️ | `Color` | **Deprecated:** This property will be retired in a future release. Switch to a styling hook or use your own custom color. | ## See also - [AgentforceColorToken](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-color-token-reference-ios.md) — the type-safe enum used to reference every token (generic and component) when supplying overrides - [Theming](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guides/ios/agentforce-mobile-sdk-ios-branding-theming.md) — how to override tokens with `AgentforceThemeOverrides` or by subclassing `AgentforceCosmosLightColors` / `AgentforceCosmosDarkColors` # AgentforceColors `open class AgentforceColorPalette(colorsMap: Map) : Colors` The Agentforce color palette: 271 tokens covering every element the SDK draws. It extends the Salesforce SharedUI `Colors` class with a component-level token for each UI element, so you can re-skin one component without disturbing anything else that shares the same base color. You rarely construct one. Start from `AgentforceLightColors` or `AgentforceDarkColors` and derive a customized copy. `AgentforceColorPalette` is the type those two objects are, and the type every colors API hands back. Declared in `AgentforceColorPalette.kt`, package `com.salesforce.android.agentforcesdk.components.theme`. There's no type named `AgentforceColors` — that's the historical file name. This page covers everything the file publishes: `AgentforceColorPalette`, the `AgentforceLightColors` and `AgentforceDarkColors` default palettes, the `AgentforceColorToken` enum, and the `withOverrides(...)` extensions. For every token's default value in both light and dark mode, see the [Color Token Reference](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-color-token-reference-android.md). ## Start from a default palette `AgentforceLightColors` and `AgentforceDarkColors` are the two ready-made palettes. Derive a customized copy with `withOverrides(...)`, which returns a new palette and never mutates the base, so the defaults stay pristine and you can derive several themes from them. ```kotlin import androidx.compose.ui.graphics.Color import com.salesforce.android.agentforcesdk.components.theme.AgentforceColorToken import com.salesforce.android.agentforcesdk.components.theme.AgentforceDarkColors import com.salesforce.android.agentforcesdk.components.theme.AgentforceLightColors import com.salesforce.android.agentforcesdk.components.theme.withOverrides val myLight = AgentforceLightColors.withOverrides( AgentforceColorToken.Accent1 to Color(0xFFFF8700), // re-skins everything accent-colored AgentforceColorToken.CarouselSurface to Color(0xFFFFF5EE), // affects only the carousel ) val myDark = AgentforceDarkColors.withOverrides( AgentforceColorToken.Accent1 to Color(0xFFFF9933), ) val manager = createCustomAgentforceThemeManager(lightColors = myLight, darkColors = myDark) ``` | Object | Signature | Description | | ----------------------- | ------------------------------------------------------- | -------------------------------------------------------------------------------------------- | | `AgentforceLightColors` | `object AgentforceLightColors : AgentforceColorPalette` | The default light-mode palette. Seeds all 47 foundation tokens plus the 8 per-mode literals. | | `AgentforceDarkColors` | `object AgentforceDarkColors : AgentforceColorPalette` | The default dark-mode palette, same shape. | Neither object declares any members of its own — every property comes from `AgentforceColorPalette`. Neither seeds the aliased or fixed-literal tokens either; those resolve on the getter, which is exactly why overriding a foundation token cascades correctly. Type inference covers the example above, but name the type when you write a helper that builds a palette: ```kotlin fun buildLightPalette(overrides: Map): AgentforceColorPalette = AgentforceLightColors.withOverrides(overrides) ``` ### Or skip the palette entirely If you only want to change a few tokens, `AgentforceThemeOverrides` is simpler — no palette object required, and any token you leave out keeps its default: ```kotlin val theming = AgentforceTheming.Overrides( AgentforceThemeOverrides( lightColors = mapOf(AgentforceColorToken.Accent1 to Color(0xFF0170CB)), darkColors = mapOf(AgentforceColorToken.Accent1 to Color(0xFF008AF7)), ) ) ``` Build a palette with `withOverrides(...)` when you want a reusable, fully resolved object; use `AgentforceThemeOverrides` for everything else. ## AgentforceColorToken `enum class AgentforceColorToken(val key: String)` A type-safe entry for each of the 271 tokens. Use it everywhere instead of raw strings — typos and renames become compile errors rather than silently ignored keys. | Member | Signature | Description | | --------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | `val key: String` | The underlying string key in the colors map. You rarely need to read it. | | `fromKey` | `fun fromKey(key: String): AgentforceColorToken?` | Looks up a token by its string key, or `null` if none matches. Use this only at the boundary with runtime-driven data such as a JSON or remote-config payload. | ```kotlin val raw: Map = parseRemoteConfig() val typed = raw.mapNotNull { (k, v) -> AgentforceColorToken.fromKey(k)?.let { it to v } }.toMap() val palette = AgentforceLightColors.withOverrides(typed) ``` ## withOverrides Two extension functions, both returning a new palette. ```kotlin fun AgentforceColorPalette.withOverrides( vararg overrides: Pair ): AgentforceColorPalette fun AgentforceColorPalette.withOverrides( overrides: Map ): AgentforceColorPalette ``` Use the vararg form for a handful of literal overrides and the map form when you assemble overrides from presets or several sources. ## How tokens resolve | Layer | Count | What it is | | --------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Foundation tokens** | 47 | The design-system base palette inherited from SharedUI `Colors` — `surface1`, `accent1`, `onSurface1`, `border1`, and so on. Each carries an explicit light and dark value. | | **Component tokens** | 224 | One token per UI element, declared on `AgentforceColorPalette` — `titleBarBackground`, `sendButtonEnabledBackground`, `carouselSurface`, and so on. Grouped into 50 component sections. | 271 tokens in total. Override a foundation token to re-skin everything derived from it; override a component token to change exactly one element. Every component token resolves its default in one of three ways: | Kind | Count | Behavior | | -------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Alias** | 209 | Falls back to a foundation token, inheriting its value _and any override you apply to it_. `carouselSurface` falls back to `surface1`, so changing `Surface1` moves the carousel too — until you override `CarouselSurface` itself. | | **Fixed literal** | 7 | A single color identical in light and dark, defined once on the getter: the two aura colors, the citation external-link color, the PDF viewer page background, and three media-viewer colors. | | **Per-mode literal** | 8 | Distinct light and dark values with no single mode-agnostic default, seeded into both default palettes: `InputBarPlaceholderColor`, `AgentAvatarLiveBackground`, `LauncherPlaceholderColor`, `UtteranceBackground`, `VoiceRoomCircleButtonSelectedBackground`, `AuraAvatarIconTint`, `MarkdownLinkColor`, `RichTextLinkColor`. | Section order and token names are kept in lock-step with the iOS `AgentforceColorPalette`, so the two platforms stay aligned. ## Members | Member | Signature | Description | | --------------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------- | | `get` | `operator fun get(token: AgentforceColorToken): Color?` | The raw seeded value for a token, or `null` when nothing is seeded. Prefer the named properties, which apply the fallback chain. | | `colorsMap` | `Map` | The underlying map, inherited from SharedUI `Colors`. | | Foundation properties | `val surface1: Color`, `val accent1: Color`, ... | 47 properties inherited from SharedUI `Colors`. | | Component properties | `val titleBarBackground: Color`, `val carouselSurface: Color`, ... | 224 read-only properties, one per component token, each applying its own fallback. | Component property names are the camelCase form of the token name: `AgentforceColorToken.SendButtonIconTint` is read as `colors.sendButtonIconTint`. `accent4` and `accent5` exist on the SharedUI base class but have no `AgentforceColorToken` and are unused by Agentforce components, so they can't be overridden through the token enum. ## Reading colors at render time The active palette comes from the theme manager, which picks light or dark based on the resolved theme mode. ```kotlin val colors = LocalAgentforceTheme.current.colors() Text( text = "Hello", color = colors.onSurface1, modifier = Modifier.background(colors.chatBackground), ) ``` ## Component groups The 224 component tokens are organized into these 50 groups. The [Color Token Reference](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-color-token-reference-android.md) lists them in this order, with each token's fallback and its light and dark defaults. | Group | Tokens | Covers | | ------------------------------- | ------ | ------------------------------------------------------------------ | | Chat scaffold | 1 | The root chat surface | | Title bar / navigation | 4 | Conversation header — title, icons, divider | | Input bar | 10 | Message composer row | | Send button | 3 | Send-message button | | Voice / stop-listening button | 3 | Voice-entry waveform button | | Agent avatar | 4 | AI and live-agent avatars in the feed | | Agent message | 2 | Agent name and message text | | User message bubble | 4 | End-user's message bubble | | Chat response / reply button | 6 | Suggested reply and chat-response buttons | | Message action buttons | 2 | Thumbs up / down / copy row | | Feedback modal | 7 | "Why wasn't this helpful?" sheet | | Toast | 8 | Info, success, warning, and error toasts | | Modal sheet | 7 | More menu, multi-modal sheet, action list, agent selector | | Inline chat error | 2 | Error inside an agent response | | Launcher | 8 | Floating launcher entry point | | Recommended utterance | 5 | Suggested-utterance chips and list | | Carousel | 7 | Horizontal card carousel | | Source / citation | 6 | Citation chips, list, external link | | Rich link | 5 | Rich link preview card | | Web link | 3 | Inline web link chip | | Record info | 5 | Record info card | | Voice room | 5 | Full-screen voice conversation | | Record selector | 5 | Record picker list | | JSON object viewer | 5 | Expandable JSON viewer | | Email | 1 | Email component surface | | Stencil / loading skeleton | 1 | Shimmer placeholder | | Action sheet | 5 | Record-actions sheet | | Toxicity | 3 | Toxicity warning block | | Form field | 13 | Shared by pre-chat fields, secure-form fields, text input, pickers | | Checkbox | 8 | Checkbox and its label | | Pre-chat form | 9 | Pre-chat form page | | Secure form | 9 | Secure form page | | Secure form link | 3 | Secure form link chip | | Generic attachment / file chip | 4 | Remove button, chip preview, border | | Image / PDF preview placeholder | 2 | Placeholder before a preview loads | | Audio attachment | 6 | Audio attachment player | | Video attachment | 3 | Video attachment preview | | PDF attachment | 2 | PDF attachment chip | | PDF viewer (full screen) | 1 | Full-screen PDF viewer | | Media viewer | 5 | Image preview and video player chrome | | Aura | 4 | Animated brand aura and avatar glow | | Markdown text | 4 | Markdown-rendered agent text | | Rich text (HTML) | 3 | HTML-rendered rich text | | Streaming card | 2 | Streaming card fade and action text | | Chat status | 2 | Status line under the chat | | Progress indicator | 3 | Typing and progress indicator | | Full-screen states | 4 | Loading, error, and onboarding screens | | Refresh button | 4 | Refresh button on the error screen | | Onboarding confirm button | 3 | Confirm button on the onboarding screen | | Generic CTA button | 3 | Generic call-to-action button | ## Notes - Values are fully opaque `#RRGGBB`. A few tokens apply transparency at the call site — the media-viewer close-button scrim is drawn at roughly 45% alpha over an opaque black token. - `OnAccent1` is white in both modes by design, since it colors text and icons sitting on the accent fill. - Setting a tint token to `Color.Unspecified` means "no tint," which lets a custom icon render in its own colors. See [Custom Icons](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-icon-type-android.md). - Check contrast in both light and dark mode for accessibility (WCAG AA). ## See also - [Color Token Reference](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-color-token-reference-android.md) — all 271 tokens with their fallbacks and light/dark default values. - [AgentforceThemeManager](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-theme-manager-android.md) — exposes the resolved palette through `colors()`. - [Theme Mode](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-theme-mode-android.md) — decides which palette renders. - [AgentforceTypography](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-typography-android.md) — the matching type scale. # AgentforceComponent `@Serializable data class AgentforceComponent` Base component model for rendering dynamic UI elements in the Agentforce Android SDK. ## Signature ```kotlin @Serializable data class AgentforceComponent( val definition: String, val name: String? = null, val properties: Map = emptyMap(), val regions: AgentforceDataRegions ) ``` ## Properties | Property | Type | Description | | ---------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------- | | definition | String | Component type identifier (e.g., "copilot/list") | | name | String? | Optional component instance name | | properties | `@Serializable(with = AgentforceViewPropertiesSerializer::class) Map` | Component-specific configuration properties with custom serialization | | regions | AgentforceDataRegions | Data regions containing nested components and content | ## Constructor | Constructor | Parameters | | ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------- | | `AgentforceComponent(definition, name, properties, regions)` | `definition: String`, `name: String? = null`, `properties: Map = emptyMap()`, `regions: AgentforceDataRegions` | ## Extension Functions | Function | Signature | Description | | ------------------- | -------------------------------------------------------------------------------------------------- | --------------------------------------- | | `getIntProperty` | `fun AgentforceComponent.getIntProperty(key: String, default: Int): Int` | Get integer property with default value | | `getListProperty` | `fun AgentforceComponent.getListProperty(key: String, default: List): List` | Get list property with default value | | `getMapProperty` | `fun AgentforceComponent.getMapProperty(key: String, default: Map): Map` | Get map property with default value | | `getStringProperty` | `fun AgentforceComponent.getStringProperty(key: String, default: String): String` | Get string property with default value | ## Related Documentation - [AgentforceClient](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-client-android.md) - Client interface - [AgentforceAPI](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/android/agentforce-api-android.md) - Backend component data source # AgentforceConfiguration `class AgentforceConfiguration` Configuration for Agentforce SDK. ## Signature ```kotlin class AgentforceConfiguration ``` ## Types ### Builder ```kotlin class Builder(authCredentialProvider: AgentforceAuthCredentialProvider) ``` Builder for AgentforceConfiguration. ### Companion ```kotlin object Companion ``` Builder for AgentforceConfiguration. ## Properties | Property | Type | Description | | ------------------------ | ----------------------------------- | --------------------------------------------- | | `agentId` | `String?` | Unique identifier for the agent | | `application` | `Application?` | Android application context | | `authCredentialProvider` | `AgentforceAuthCredentialProvider` | Provides authentication tokens | | `cameraUriProvider` | `AgentforceCameraUriProvider?` | Provides URIs for camera captures | | `connectionInfo` | `AgentforceConnectionInfo?` | Connection details for the SDK | | `dataProvider` | `DataProvider?` | Custom data provider for content | | `delegate` | `AgentforceUIDelegate?` | Custom UI delegate for advanced customization | | `featureFlagSettings` | `AgentforceFeatureFlagSettings?` | Feature flag settings for the SDK | | `instrumentationHandler` | `AgentforceInstrumentationHandler?` | Handles analytics and instrumentation events | | `isVoiceModeEnabled` | `Boolean` | Whether voice mode is enabled | | `logger` | `Logger?` | Custom logger for SDK events | | `navigation` | `Navigation?` | Custom navigation handler | | `network` | `Network?` | Custom network implementation | | `onboardingManager` | `AgentforceOnboardingManager?` | Manages onboarding flow | | `permission` | `Permissions?` | Permission management interface | | `readbackManaging` | `AgentforceReadbackManaging?` | Manages readback functionality | | `salesforceDomain` | `String?` | Salesforce instance domain | | `serviceApiURL` | `String?` | Service API URL | | `themeManager` | `AgentforceThemeManager` | Theme management for UI components | | `user` | `User?` | User information interface | | `viewProvider` | `AgentforceViewProvider?` | Provides custom views for UI components | | `voiceManaging` | `AgentforceVoiceManaging?` | Manages voice functionality | ## Builder Functions | Method | Parameters | Return Type | Description | | ----------------------------------------------------------------------- | ------------------------------------------------- | ------------------------- | -------------------------------- | | `build()` | None | `AgentforceConfiguration` | Builds the configuration | | `setAgentId(id: String?)` | `id: String?` | `Builder` | Sets the agent ID | | `setApplication(application: Application?)` | `application: Application?` | `Builder` | Sets the application context | | `setCameraUriProvider(cameraUriProvider: AgentforceCameraUriProvider?)` | `cameraUriProvider: AgentforceCameraUriProvider?` | `Builder` | Sets the camera URI provider | | `setConnectionInfo(connectionInfo: AgentforceConnectionInfo?)` | `connectionInfo: AgentforceConnectionInfo?` | `Builder` | Sets connection information | | `setDataProvider(dataProvider: DataProvider?)` | `dataProvider: DataProvider?` | `Builder` | Sets the data provider | | `setDelegate(delegate: AgentforceUIDelegate?)` | `delegate: AgentforceUIDelegate?` | `Builder` | Sets the UI delegate | | `setFeatureFlagSettings(flags: AgentforceFeatureFlagSettings)` | `flags: AgentforceFeatureFlagSettings` | `Builder` | Sets feature flag settings | | `setInstrumentationHandler(handler: AgentforceInstrumentationHandler?)` | `handler: AgentforceInstrumentationHandler?` | `Builder` | Sets the instrumentation handler | | `setLogger(logger: Logger?)` | `logger: Logger?` | `Builder` | Sets the logger | | `setNavigation(navigation: Navigation?)` | `navigation: Navigation?` | `Builder` | Sets the navigation handler | | `setNetwork(network: Network?)` | `network: Network?` | `Builder` | Sets the network implementation | | `setOnboardingManager(onboardingManager: AgentforceOnboardingManager?)` | `onboardingManager: AgentforceOnboardingManager?` | `Builder` | Sets the onboarding manager | | `setPermission(permission: Permissions?)` | `permission: Permissions?` | `Builder` | Sets the permission interface | | `setReadbackManaging(readbackManaging: AgentforceReadbackManaging?)` | `readbackManaging: AgentforceReadbackManaging?` | `Builder` | Sets the readback manager | | `setSalesforceDomain(domain: String?)` | `domain: String?` | `Builder` | Sets the Salesforce domain | | `setServiceApiURL(serviceApiURL: String?)` | `serviceApiURL: String?` | `Builder` | Sets the service API URL | | `setThemeManager(themeManager: AgentforceThemeManager?)` | `themeManager: AgentforceThemeManager?` | `Builder` | Sets the theme manager | | `setUser(user: User?)` | `user: User?` | `Builder` | Sets the user interface | | `setViewProvider(provider: AgentforceViewProvider?)` | `provider: AgentforceViewProvider?` | `Builder` | Sets the view provider | | `setVoiceManaging(voiceManaging: AgentforceVoiceManaging?)` | `voiceManaging: AgentforceVoiceManaging?` | `Builder` | Sets the voice manager | | `setVoiceModeEnabled(enabled: Boolean)` | `enabled: Boolean` | `Builder` | Sets voice mode enabled state | ## Companion Functions | Method | Parameters | Return Type | Description | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | ------------------------------------------------- | | `builder(authCredentialProvider: AgentforceAuthCredentialProvider)` | `authCredentialProvider: AgentforceAuthCredentialProvider` | `AgentforceConfiguration.Builder` | Creates a new builder instance | | `createFromEmployeeAgentConfiguration(authCredentialProvider: AgentforceAuthCredentialProvider, employeeAgentConfiguration: EmployeeAgentConfiguration, application: Application, baseFeatureFlags: AgentforceFeatureFlagSettings? = null)` | `authCredentialProvider: AgentforceAuthCredentialProvider`, `employeeAgentConfiguration: EmployeeAgentConfiguration`, `application: Application`, `baseFeatureFlags: AgentforceFeatureFlagSettings? = null` | `AgentforceConfiguration.Builder` | Creates builder from employee agent configuration | | `createFromServiceAgentConfiguration(authCredentialProvider: AgentforceAuthCredentialProvider? = null, serviceAgentConfiguration: ServiceAgentConfiguration, application: Application, baseFeatureFlags: AgentforceFeatureFlagSettings? = null)` | `authCredentialProvider: AgentforceAuthCredentialProvider? = null`, `serviceAgentConfiguration: ServiceAgentConfiguration`, `application: Application`, `baseFeatureFlags: AgentforceFeatureFlagSettings? = null` | `AgentforceConfiguration.Builder` | Creates builder from service agent configuration | ## Related Documentation - [AgentforceMode](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-mode-android.md) - [EmployeeAgentConfiguration](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/employee-agent-configuration-android.md) - [ServiceAgentConfiguration](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/service-agent-configuration-android.md) - [AgentforceClient](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-client-android.md) # AgentforceConfiguration ## Overview Comprehensive configuration object that encapsulates all dependencies and settings required for Agentforce SDK initialization. It serves as the central configuration hub that brings together all the components needed to create a fully functional Agentforce integration. ## Declaration ```swift struct AgentforceConfiguration ``` ## Properties | Property | Type | Required? | Description | | ----------------------------- | ---------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------- | | user | User | Yes | The current user context providing authentication state and user-specific settings | | availableAgents | [AgentInfo]? | No | Optional list of available agents that can be used for conversation targeting | | agentforceCopier | AgentforceCopying? | No | Optional clipboard integration provider for copy-to-clipboard functionality | | enableDebugSettings | Bool | No | Development and debugging flag that enables additional diagnostic tools and settings (default: false) | | ignoreWelcomeMessage | Bool | No | Flag whether or not the welcome message should be ignored (default: false) | | forceConfigEndPoint | String | Yes | The primary Salesforce org endpoint URL used for service discovery and configuration | | dataProvider | AgentforceDataProviding? | No | Optional custom data provider for Salesforce record and metadata access | | imageProvider | AgentforceImageProviding? | No | Optional custom image provider for loading and caching visual content | | instrumentationHandler | AgentforceInstrumentationHandling? | No | Optional instrumentation handler for analytics, performance monitoring, and event tracking | | agentforceFeatureFlagSettings | AgentforceFeatureFlagSettings | Yes | Feature flag configuration controlling SDK behavior and experimental functionality | | agentforceConnectionInfo | AgentforceConnectionInfo? | No | Optional pre-configured connection information for Agentforce services | | salesforceNetwork | SalesforceNetwork.Network? | No | Network abstraction layer providing HTTP communication capabilities | | salesforceNavigation | SalesforceNavigation.Navigation? | No | Optional navigation handler for integrating with your application's navigation system | | salesforceLogger | SalesforceLogging.Logger? | No | Optional logging provider for SDK diagnostic and debugging information | | ttsVoiceProvider | AgentforceReadbackHandler? | No | Optional text-to-speech provider for voice output capabilities | | speechRecognizer | AgentforceSpeechTranscriber? | No | Optional speech recognition provider for voice input capabilities | | themeManager | AgentforceThemeManager | No | Optional themeManager provider for comprehensive visual customization (default: AgentforceDefaultThemeManager()) | | themeOverrides | AgentforceThemeOverrides? | No | Optional sparse bag of color, font, icon, and display-name token overrides layered on top of the theme manager | | serviceApiURL | String? | No | The service API URL for service agent configurations | ## Methods | Method | Signature | Description | | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------- | | init | init(user:availableAgents:agentforceCopier:enableDebugSettings:ignoreWelcomeMessage:forceConfigEndpoint:dataProvider:imageProvider:instrumentationHandler:agentforceFeatureFlagSettings:agentforceConnectionInfo:salesforceNetwork:salesforceNavigation:salesforceLogger:ttsVoiceProvider:speechRecognizer:themeManager:themeOverrides:serviceApiURL:) | Creates a comprehensive Agentforce configuration with all available customization options | ## Configuration Patterns ```swift let config = AgentforceConfiguration( user: currentUser, forceConfigEndpoint: "https://myorg.salesforce.com", agentforceFeatureFlagSettings: defaultFlags, salesforceNetwork: networkManager, salesforceNavigation: navigationHandler ) ``` ```swift let config = AgentforceConfiguration( user: currentUser, forceConfigEndpoint: "https://myorg.salesforce.com", dataProvider: customDataProvider, imageProvider: customImageLoader, instrumentationHandler: analyticsHandler, agentforceFeatureFlagSettings: productionFlags, salesforceNetwork: networkManager, salesforceNavigation: navigationHandler, themeManager: customThemeManager, ttsVoiceProvider: voiceHandler, speechRecognizer: speechHandler ) ``` ```swift let voiceFeatureFlags = AgentforceFeatureFlagSettings( enableVoice: true, shouldBlockMicrophone: false ) let config = AgentforceConfiguration( user: currentUser, forceConfigEndpoint: "https://myorg.salesforce.com", agentforceFeatureFlagSettings: voiceFeatureFlags, salesforceNetwork: networkManager, ttsVoiceProvider: textToSpeechProvider, speechRecognizer: speechRecognitionProvider ) ``` ## See also - [Theming](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guides/ios/agentforce-mobile-sdk-ios-branding-theming.md) — how `themeManager` and `themeOverrides` combine to customize colors, fonts, icons, and display names # AgentforceConnectionInfo ## Overview Structure that encapsulates connection information for Agentforce services, including the service API URL and tenant identifier. This information is used to route requests to the appropriate Agentforce service endpoints. ## Declaration ```swift struct AgentforceConnectionInfo: Codable ``` ## Properties | Property | Type | Description | | ---------- | -------- | --------------------------------------------------------------------------------------------------------- | | `sfapURL` | `String` | The Salesforce API Platform (SFAP) URL used for Agentforce service communication. | | `tenantId` | `String` | The tenant identifier that uniquely identifies the Salesforce organization's Agentforce service instance. | ## Methods | Method | Signature | Description | | ------ | ------------------------- | ----------------------------------------------------------------------------- | | `init` | `init(sfapURL:tenantId:)` | Creates a connection info instance with the specified SFAP URL and tenant ID. | ## Configuration Patterns ```swift // Provide connection information directly let connectionInfo = AgentforceConnectionInfo( sfapURL: "https://api.salesforce.com", tenantId: "core/prod/00D000000000000AAA" ) let config = AgentforceConfiguration( user: currentUser, forceConfigEndpoint: "https://myorg.salesforce.com", agentforceFeatureFlagSettings: featureFlags, agentforceConnectionInfo: connectionInfo, salesforceNetwork: networkManager ) ``` When `agentforceConnectionInfo` is `nil` in `AgentforceConfiguration`, the SDK automatically queries connection information from the configured `forceConfigEndPoint` during initialization. ```swift let config = AgentforceConfiguration( user: currentUser, forceConfigEndpoint: "https://myorg.salesforce.com", agentforceFeatureFlagSettings: featureFlags, agentforceConnectionInfo: nil, // SDK will discover automatically salesforceNetwork: networkManager ) ``` # AgentforceContextManager `class AgentforceContextManager(agentforcePageContext: AgentforcePageContext? = null) : AgentforceContextManaging` Manages conversation context and page context for Agentforce conversations. ## Signature ```kotlin class AgentforceContextManager( var agentforcePageContext: AgentforcePageContext? = null ) : AgentforceContextManaging ``` ## Constructors | Constructor | Description | | ------------------------------------------------------------------- | ----------- | | `constructor(agentforcePageContext: AgentforcePageContext? = null)` | | ## Properties | Property | Type | Description | | ----------------------- | ---------------------------- | ----------------------------- | | `agentforcePageContext` | `var AgentforcePageContext?` | Current page context variable | ## Functions | Method | Return Type | Description | | ----------------------------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------ | | `currentContext()` | `MutableMap` | | | `resetPageContext()` | `Unit` | | | `setAdditionalContextVariables(CopilotAdditionalContext context)` | `Unit` | | | `updatePageContext(AgentforcePageContext context)` | `Unit` | Set current page context variable Use resetPageContext if you wish to make the page context null | ## Nested Types ### Companion ```kotlin object Companion ``` #### Companion Methods | Method | Return Type | Description | | ------------------------------------------------- | ------------------------------ | ----------- | | `validateTypes(CopilotAdditionalContext context)` | `List` | | ## Related Documentation - [AgentforceClient](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-client-android.md) - [AgentforceConversation](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-conversation-android.md) # AgentforceConversation ```kotlin class AgentforceConversation( agentId: String? = null, sessionId: String? = null, configuration: AgentforceConfiguration, connectionInfo: AgentforceConnectionInfo? = null, conversationService: ConversationService, logger: Logger? = null, conversationState: StateFlow = MutableStateFlow(AgentforceConversationState.INITIALIZING), onSessionUpdated: (AgentforceConversation, String?) -> Unit = { _, _ -> } ) : AgentConversation ``` ## Constructors - `AgentforceConversation(String?, String?, AgentforceConfiguration, AgentforceConnectionInfo?, ConversationService, Logger?, StateFlow, Function2)` ## Properties | Property | Type | Mutability | Description | | --------------------- | -------------------------------------- | ---------- | ------------------------------------------------------ | | agentId | String? | var | The identifier of the agent handling this conversation | | conversationManager | ConversationManaging | var | Internal conversation management interface | | conversationState | StateFlow | val | Flow providing real-time conversation state updates | | id | String | val | Unique identifier for this conversation | | recommendedUtterances | StateFlow> | val | Flow of recommended utterances | | sessionId | String? | var | Session identifier for conversation continuity | | sessionScope | CoroutineScope | var | Coroutine scope for session operations | ## Functions | Function | Signature | Description | | ------------------------------ | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | | endConversation | `suspend fun endConversation(): Unit` | Ends the current conversation session | | getCurrentAgent | `fun getCurrentAgent(): AgentData` | Get current agent data | | resetSession | `open override fun resetSession(): Unit` | Resets the Agentforce session container | | resetSession | `fun resetSession(String): Unit` | | | retrieveTranscript | `suspend fun retrieveTranscript(): InputStream` | Retrieve conversation transcript as a PDF InputStream | | sendTypingIndicator | `suspend fun sendTypingIndicator(): Unit` | Sends a typing indicator for MIAW conversations when user is typing | | sendUtterance | `open suspend override fun sendUtterance(String, AgentforceAttachment?): Unit` | Send an utterance to Agentforce | | setAdditionalContext | `open suspend override fun setAdditionalContext(CopilotAdditionalContext): Unit` | Updates the current context variables that will be sent to Agentforce on subsequent messages | | startSession | `suspend fun startSession(): Unit` | | | updateRecommendationUtterances | `open override fun updateRecommendationUtterances(List): Unit` | | ## Inherited Functions - clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait # AgentforceConversation `class AgentforceConversation` Concrete implementation of the AgentConversation protocol providing full conversation management capabilities. ## Overview `AgentforceConversation` orchestrates all aspects of a conversation session including service communication, state management, message processing, and context handling. This class serves as the primary interface between application code and the underlying Agentforce service infrastructure. ## Declaration ```swift class AgentforceConversation ``` ## Topics This section provides detailed information about the AgentConversation class properties and methods. ### Instance Properties | Property | Type | Description | | ---------------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `agentId` | `String?` | The identifier of the agent handling this conversation. Set during conversation initialization and may be updated if agent switching occurs during the conversation. | | `conversationId` | `UUID` | Unique identifier for this conversation instance. Generated when the conversation is created and provides a stable identifier for tracking, analytics, and debugging purposes. | | `conversationState` | `Published.Publisher` | Publisher providing real-time conversation state updates. | | `deliveryStatusEvents` | `AnyPublisher` | Publisher for delivery status events. | | `hasEnded` | `Bool` | Indicates whether the conversation has been explicitly ended by the user. When true, the conversation has been ended and should show the ended message. Set to true when endConversation() is called, false when sendUtterance() resumes conversation. | | `isHumanAgentMode` | `Bool` | Indicates whether the conversation is with a human agent. When true, allows multiple consecutive user messages without waiting for responses. | | `messages` | `Published<[AgentforceMessage]>.Publisher` | Publisher providing access to the complete conversation message history. Emits updates whenever new messages are added or existing messages are modified. | | `sessionId` | `String?` | The unique session identifier for this conversation. | | `statusEvents` | `AnyPublisher` | Publisher for status events (typing indicators, etc.). | | `systemEvents` | `AnyPublisher` | Publisher for system events (participant changes, escalations, etc.). | ### Instance Methods | Method | Parameters | Return Type | Description | | ----------------------------------------------- | ------------------------------------------------------ | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `closeConversation()` | None | `async throws` | Closes the current conversation session and clears the session ID to prevent resumption. | | `downloadTranscript()` | None | `async throws -> TranscriptResponse` | Downloads a PDF transcript of the current conversation. | | `endConversation()` | None | `async throws` | Ends the current conversation session. | | `recommendedUtterances()` | None | `async throws -> [String]` | Manually retrieve recommended utterances (fetches fresh data). | | `reset()` | None | `async throws` | Removes all messages from the conversation. | | `sendUtterance(utterance:attachment:)` | `utterance: String, attachment: AgentforceAttachment?` | `async` | Sends a user message to the agent with optional file attachments. Initiates a complete message exchange cycle, sending the user's input to the Agentforce service and preparing to receive agent responses. | | `setAdditionalContext(context:)` | `context: [AgentforceVariable]` | `async throws` | Updates the conversation context with additional variables that inform agent responses. Context variables provide essential information that helps agents understand the current situation and provide more relevant, accurate responses. | | `updateRecommendedUtterances(recommendations:)` | `recommendations: [String]` | None | Updates the conversation with recommended utterances for quick user interaction. | ## Architecture Overview The conversation implementation follows a layered architecture: - **Public API Layer**: Implements the `AgentConversation` protocol for application interaction - **State Management Layer**: Tracks conversation state and publishes updates - **Service Communication Layer**: Handles network communication with Agentforce services - **Message Processing Layer**: Processes incoming responses and manages conversation history - **Context Management Layer**: Maintains conversation context and user information ## Thread Safety The conversation implementation is designed for thread safety: - Public methods can be safely called from any thread - Internal state updates are properly synchronized - Publishers emit updates from appropriate threading contexts - Asynchronous operations are properly managed to prevent race conditions # AgentforceConversation ## Overview Concrete implementation of the AgentConversation protocol providing full conversation management capabilities. It orchestrates all aspects of a conversation session including service communication, state management, message processing, and context handling. This class serves as the primary interface between application code and the underlying Agentforce service infrastructure. ## Declaration ```swift class AgentforceConversation ``` ## Properties | Property | Type | Description | | -------------------- | ------------------------------------------------ | ------------------------------------------------------------------------ | | agentId | String? | The identifier of the agent handling this conversation | | conversationId | UUID | Unique identifier for this conversation instance | | conversationState | Published.Publisher | Publisher providing real-time conversation state updates | | messages | Published<[AgentforceMessage]>.Publisher | Publisher providing access to the complete conversation message history | | sessionId | String? | The unique session identifier for this conversation | | hasEnded | Bool | Indicates whether the conversation has been explicitly ended by the user | | isHumanAgentMode | Bool | Indicates whether the conversation is with a human agent | | statusEvents | AnyPublisher | Publisher for status events (typing indicators, etc.) | | systemEvents | AnyPublisher | Publisher for system events (participant changes, escalations, etc.) | | deliveryStatusEvents | AnyPublisher | Publisher for delivery status events | ## Methods | Method | Signature | Description | | --------------------------- | ------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------- | | sendUtterance | func sendUtterance(utterance: String, attachment: AgentforceAttachment?) async | Sends a user message to the agent with optional file attachments | | setAdditionalContext | func setAdditionalContext(context: [AgentforceVariable]) | Updates the conversation context with additional variables that inform agent responses | | closeConversation | func closeConversation() async throws | Closes the current conversation session and clears the session ID to prevent resumption | | endConversation | func endConversation() async throws | Ends the current conversation session | | reset | func reset() async throws | Removes all messages from the conversation | | recommendedUtterances | func recommendedUtterances() async throws -> [String] | Manually retrieve recommended utterances (fetches fresh data) | | updateRecommendedUtterances | func updateRecommendedUtterances(recommendations: [String]) | Updates the conversation with recommended utterances for quick user interaction | | downloadTranscript | func downloadTranscript() async throws -> TranscriptResponse | Downloads a PDF transcript of the current conversation | # AgentforceConversationState ```kotlin enum AgentforceConversationState : Enum ``` ## Properties | Property | Type | Mutability | Description | | -------- | ---------------------------------------- | ---------- | ----------------------- | | entries | EnumEntries | val | Enum entries collection | | name | String | val | Enum constant name | | ordinal | Int | val | Enum constant ordinal | ## Functions | Function | Signature | Description | | -------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | valueOf | `fun valueOf(String): AgentforceConversationState` | Returns the enum constant of this type with the specified name. The string must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.) | | values | `fun values(): Array` | Returns an array containing the constants of this enum type, in the order they're declared. | ## Enum Constants - `INITIALIZING` - `ACTIVE` - `ERROR` - `REFRESHING` ## Inherited Functions - clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait # AgentforceConversationState ## Overview Represents the current operational state of an Agentforce conversation session. This enumeration tracks the lifecycle stages of a conversation, enabling applications to respond appropriately to state changes and provide relevant user feedback. Understanding session state is crucial for managing user expectations and handling error conditions gracefully. ## Declaration ```swift enum AgentforceConversationState ``` ## Properties | Property | Type | Description | | ------------ | ---- | ----------------------------------------------------------------------------------- | | initializing | case | The conversation is establishing its initial connection with the Agentforce service | | active | case | The conversation session is fully established and ready for user interaction | | sending | case | A message is being sent to Agentforce | | receiving | case | Waiting for a response from Agentforce | | refreshing | case | The conversation session is attempting to recover from a temporary disruption | | ended | case | The conversation has been explicitly ended by the user | | error | case | An error has occurred that prevents normal conversation operation | # AgentforceDataProviderErrors ## Overview Errors that can occur when using `AgentforceDataProviding` implementations. These errors indicate issues with data provider functionality and help developers understand and handle data access failures appropriately. ## Declaration ```swift enum AgentforceDataProviderErrors ``` ## Methods | Method | Signature | Description | | ------------------------- | --------------------------- | -------------------------------------------------------------------- | | `NotImplemented` | `case NotImplemented` | Indicates that a required method or feature has not been implemented | | Equatable Implementations | `Equatable-Implementations` | Default equatable implementations | | Error Implementations | `Error-Implementations` | Default error implementations | # AgentforceDataProviding ## Overview Protocol for providing data access functionality to the Agentforce SDK. This protocol serves as the bridge between the Agentforce SDK and your application's data layer, typically connecting to Salesforce APIs. Implementations should provide access to Salesforce records, object metadata, and query capabilities while respecting security, caching, and performance requirements. ## Declaration ```swift protocol AgentforceDataProviding ``` ## Methods | Method | Signature | Description | | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------- | | `objectInfo(for:cachePolicy:transactionId:)` | `func objectInfo(for: String, cachePolicy: AgentforceCachePolicy, transactionId: String?) async throws -> AgentforceObjectRepresentation` | Retrieves metadata information for a Salesforce object type | | `objectInfos(forObjectTypes:cachePolicy:transactionId:)` | `func objectInfos(forObjectTypes: [String], cachePolicy: AgentforceCachePolicy, transactionId: String?) async throws -> [AgentforceUIAPIObjectInfo]` | Retrieves metadata information for multiple Salesforce object types | | `query(for:cachePolicy:transactionId:)` | `func query(for: AgentforceQueryData, cachePolicy: AgentforceCachePolicy, transactionId: String?) async throws -> [String: Any]` | Executes a query and returns matching records | | `record(for:recordId:fields:cachePolicy:transactionId:)` | `func record(for: String, recordId: String, fields: [String], cachePolicy: AgentforceCachePolicy, transactionId: String?) async throws -> AgentforceRecordRepresentation` | Retrieves a single record with specified fields | | `record(forLayoutType:recordId:modes:cachePolicy:transactionId:)` | `func record(forLayoutType: String, recordId: String, modes: [AgentforceAccessMode], cachePolicy: AgentforceCachePolicy, transactionId: String?) async throws -> AgentforceRecordRepresentation` | Retrieves a single record using layout-based field selection | | `records(forLayoutType:recordIds:modes:cachePolicy:transactionId:)` | `func records(forLayoutType: String, recordIds: [String], modes: [AgentforceAccessMode]?, cachePolicy: AgentforceCachePolicy, transactionId: String?) async throws -> [AgentforceUIAPIRecord]` | Retrieves multiple records using layout-based field selection | | `records(forObjectType:recordIds:fields:cachePolicy:transactionId:)` | `func records(forObjectType: String, recordIds: [String], fields: [String], cachePolicy: AgentforceCachePolicy, transactionId: String?) async throws -> [AgentforceUIAPIRecord]` | Retrieves multiple records with specified fields in a batch operation | # AgentforceDefaultThemeManager ## Overview Default implementation of the Agentforce theme management system with built-in Salesforce design tokens. `AgentforceDefaultThemeManager` provides a complete theming solution that handles light/dark mode switching, dynamic font sizing, and comprehensive visual customization using Salesforce's Cosmos design system. It serves as both a production-ready theme manager and a reference implementation for custom theme development. ## Declaration ```swift class AgentforceDefaultThemeManager ``` ## Properties | Property | Type | Description | | ------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------- | | `colorScheme` | `ColorScheme` | Current color scheme applied to UI components | | `colors` | `AgentforceTheme.Colors` | Active color palette automatically selected based on current color scheme | | `dimensions` | `AgentforceTheme.Dimensions` | Spacing, sizing, and layout measurements from Salesforce Cosmos design system | | `dynamicFonts` | `Bool` | Controls whether fonts use dynamic sizing based on accessibility preferences | | `fonts` | `AgentforceTheme.Fonts` | Active font system automatically selected based on dynamic font preferences | | `overrideColorSchemeWithSystem` | `Bool` | Determines whether UI components should respect system-wide color scheme preferences | | `shapes` | `AgentforceTheme.Shapes` | Border radius, corner styles, and geometric properties from Salesforce Cosmos design system | ## Methods | Method | Signature | Description | | ------------------------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------- | | `init(themeMode:dynamicFonts:)` | `init(themeMode: AgentforceThemeMode, dynamicFonts: Bool)` | Creates a new theme manager with specified appearance and accessibility preferences | ## Usage Patterns ### Basic Configuration ```swift let themeManager = AgentforceDefaultThemeManager( themeMode: .system, dynamicFonts: true ) ``` ### Custom Theme Mode ```swift let darkThemeManager = AgentforceDefaultThemeManager( themeMode: .dark, dynamicFonts: false ) ``` # AgentforceDesignSystem ## Overview Design system components and guidelines for Agentforce conversations. ## Declaration ```swift enum AgentforceDesignSystem ``` ## Methods | Method | Signature | Description | | -------------- | ------------------- | -------------------------------------------------------------------------------- | | `BorderRadius` | `enum BorderRadius` | An enumeration representing border radius sizes based on Lightning Design System | | `BorderWidth` | `enum BorderWidth` | Border width enumeration for design system | | `Spacing` | `enum Spacing` | Spacing enumeration for design system | # AgentforceFeatureFlagSettings `data class AgentforceFeatureFlagSettings` Configuration structure controlling feature availability and experimental functionality within the Agentforce SDK. Provides fine-grained control over SDK capabilities, enabling progressive feature rollout, A/B testing scenarios, and organization-specific customizations. ## Signature ```kotlin data class AgentforceFeatureFlagSettings ``` ## Properties | Property | Type | Description | | ------------------------------------ | --------- | ---------------------------------------------------------------------------------------------------- | | `enableMultiModalInput` | `Boolean` | Enables rich media input capabilities, including image uploads. Doesn't enable other document types. | | `enablePDFUpload` | `Boolean` | Enables specific support for PDF document uploads and processing. | | `enableLongPauseSpeechTranscription` | `Boolean` | Enables long pause speech transcription capabilities. | | `enableMultiAgent` | `Boolean` | Enables multi-agent conversation capabilities including agent discovery, switching, and comparison. | | `enableTheming` | `Boolean` | Enables theming capabilities for UI customization. | | `enableOnboarding` | `Boolean` | Enables onboarding opt-in UI. | | `enableVoice` | `Boolean` | Enables voice input capabilities for conversations. | ## Methods | Method | Signature | Description | | --------- | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | | `builder` | `fun builder(): Builder` | Creates a new builder instance for constructing feature flag settings. | | `build` | `fun build(): AgentforceFeatureFlagSettings` | Builds the feature flag configuration with specified public feature enablement and optional internal flags. | ## Configuration Patterns ```kotlin val settings = AgentforceFeatureFlagSettings.builder() .enableMultiModalInput(false) .enablePDFUpload(false) .enableMultiAgent(false) .enableVoice(false) .build() ``` ```kotlin val settings = AgentforceFeatureFlagSettings.builder() .enableMultiModalInput(true) .enablePDFUpload(true) .enableMultiAgent(true) .enableVoice(true) .build() ``` # AgentforceFeatureFlagSettings ## Overview Configuration structure controlling feature availability and experimental functionality within the Agentforce SDK. Provides fine-grained control over SDK capabilities, enabling progressive feature rollout, A/B testing scenarios, and organization-specific customizations. ## Declaration ```swift struct AgentforceFeatureFlagSettings ``` ## Properties | Property | Type | Description | | ----------------------- | ------ | ---------------------------------------------------------------------------------------------------- | | `enableMultiModalInput` | `Bool` | Enables rich media input capabilities, including image uploads. Doesn't enable other document types. | | `enablePDFFileUpload` | `Bool` | Enables specific support for PDF document uploads and processing. | | `multiAgent` | `Bool` | Enables multi-agent conversation capabilities including agent discovery, switching, and comparison. | | `shouldBlockMicrophone` | `Bool` | Controls microphone access for voice input features. | | `enableVoice` | `Bool` | Enables voice input capabilities for conversations. | | `enableOnboarding` | `Bool` | Enables onboarding opt-in UI. | ## Methods | Method | Signature | Description | | ----------- | ------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------- | | `init` | `init(enableMultiModalInput:enablePDFFileUpload:multiAgent:shouldBlockMicrophone:enableVoice:enableOnboarding:internalFlags:)` | Creates a feature flag configuration with specified public feature enablement and optional internal flags. | | `subscript` | `subscript(_:) -> Bool` | Access internal feature flag values via string key. This provides public access for demo apps and external usage. | ## Configuration Patterns ```swift let settings = AgentforceFeatureFlagSettings( enableMultiModalInput: false, enablePDFFileUpload: false, multiAgent: false ) ``` ```swift let settings = AgentforceFeatureFlagSettings( enableMultiModalInput: true, enablePDFFileUpload: true, multiAgent: true, enableVoice: true ) ``` # AgentforceInstrumentationEvent `interface AgentforceInstrumentationEvent` Base interface for all instrumentation events in the Agentforce SDK. ## Properties | Property | Signature | Description | | ----------- | ----------------------------------- | ------------------------------ | | `eventInfo` | `abstract val eventInfo: EventInfo` | Event information and metadata | ## Nested Types The following types implement `AgentforceInstrumentationEvent`: | Type | Signature | | ---------------------------------- | -------------------------------------------------------------------------------------------------------- | | `AgentforceBootstrapEvent` | `data class AgentforceBootstrapEvent(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `AgentforceCardLoadEvent` | `data class AgentforceCardLoadEvent(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `AgentforceEngagementEvent` | `data class AgentforceEngagementEvent(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `AgentforceErrorReceived` | `data class AgentforceErrorReceived(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `AgentforceESTypeDecompose` | `data class AgentforceESTypeDecompose(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `AgentforceFetchAgents` | `data class AgentforceFetchAgents(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `AgentforceFetchObjectInfo` | `data class AgentforceFetchObjectInfo(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `AgentforceFetchRecords` | `data class AgentforceFetchRecords(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `AgentforceInput` | `data class AgentforceInput(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `AgentforceInteractionEvent` | `data class AgentforceInteractionEvent(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `AgentforceListViewLoad` | `data class AgentforceListViewLoad(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `AgentforceMultiAgentEvent` | `data class AgentforceMultiAgentEvent(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `AgentforceMultiModalEvent` | `data class AgentforceMultiModalEvent(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `AgentforcePlannerBotResponse` | `data class AgentforcePlannerBotResponse(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `AgentforceResetChat` | `data class AgentforceResetChat(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `AgentforceResponseReceived` | `data class AgentforceResponseReceived(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `AgentforceSwitchAgentEvent` | `data class AgentforceSwitchAgentEvent(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `AgentforceTypeError` | `data class AgentforceTypeError(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `AgentforceValidationFailureEvent` | `data class AgentforceValidationFailureEvent(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `AgentVoiceResponseTime` | `data class AgentVoiceResponseTime(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | | `TimeToStartVoiceChatRoom` | `data class TimeToStartVoiceChatRoom(val eventInfo: EventInfo) : AgentforceInstrumentationEvent` | ## Related Documentation - [AgentforceMessage](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/android/agentforce-message-android.md) - [AgentforceInstrumentationHandler](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-instrumentation-handler-android.md) - [AgentforceConversation](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-conversation-android.md) - [AgentforceClient](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-client-android.md) # AgentforceInstrumentationHandler `interface AgentforceInstrumentationHandler` Interface for handling instrumentation events in the Agentforce SDK. ## Functions | Function | Signature | | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | `handleInstrumentationEvent` | `abstract fun handleInstrumentationEvent(instrumentationEvent: AgentforceInstrumentationEvent, transactionId: String? = null)` | ## Related Documentation - [AgentforceInstrumentationEvent](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-instrumentation-event-android.md) - [AgentforceConversation](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-conversation-android.md) - [AgentforceClient](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-client-android.md) # AgentforceLauncher `struct AgentforceLauncher` A SwiftUI view that provides a floating launcher interface for accessing the Agentforce conversation UI. ## Overview The `AgentforceLauncher` serves as the primary entry point for users to interact with the Agentforce AI assistant. It displays as a persistent, floating interface element that shows conversation status and provides multiple ways to initiate or continue conversations. ## Declaration ```swift @MainActor struct AgentforceLauncher ``` ## Properties | Property | Type | Description | | ---------------------- | -------------------------- | --------------------------------------------------------------------------------- | | body | some View | The launcher's UI implementation | | openTranscribing | (() -> Void)? | Callback to open the conversation with voice input active | | openWithKeyboardClosed | (((() -> Void)?) -> Void)? | Callback to open the conversation without keyboard, optionally running completion | | openWithKeyboardOpen | (() -> Void)? | Callback to open the conversation with keyboard input ready | ## Example Usage ```swift // Create launcher with conversation view model let launcher = AgentforceLauncher( viewModel: conversationViewModel, launchChatView: { presentConversationUI() } ) // Embed in your app's main view ZStack { MainAppContent() VStack { Spacer() HStack { Spacer() launcher .padding() } } } ``` # AgentforceMessage `@Serializable data class AgentforceMessage` Data class representing a message in the Agentforce SDK with serialization support. ## Constructors | Constructor | Signature | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `AgentforceMessage` | `constructor(id: String, message: String? = null, text: String? = null, type: String, messageType: String? = null, feedbackId: String? = null, widget: String? = null, result: List? = null, confirm: List? = null, collect: List? = null, choices: List? = null, failureCode: String? = null, errors: List? = null, isContentSafe: Boolean? = true, citedReferences: List? = null, lightningType: String? = null, isPartial: Boolean = false, value: String? = null, offset: Int = 0, timeStamp: Long = Date().time, language: String? = null, reason: String = "")` | ## Properties | Property | Signature | | ----------------- | ---------------------------------------------------- | | `choices` | `val choices: List? = null` | | `citedReferences` | `val citedReferences: List? = null` | | `collect` | `val collect: List? = null` | | `confirm` | `val confirm: List? = null` | | `errors` | `val errors: List? = null` | | `failureCode` | `val failureCode: String? = null` | | `feedbackId` | `val feedbackId: String? = null` | | `id` | `val id: String` | | `isContentSafe` | `val isContentSafe: Boolean? = true` | | `isPartial` | `@Transient val isPartial: Boolean = false` | | `language` | `val language: String? = null` | | `lightningType` | `val lightningType: String? = null` | | `message` | `var message: String?` | | `messageType` | `val messageType: String? = null` | | `offset` | `val offset: Int = 0` | | `reason` | `val reason: String` | | `result` | `val result: List? = null` | | `text` | `val text: String? = null` | | `timeStamp` | `val timeStamp: Long` | | `type` | `val type: String` | | `value` | `val value: String? = null` | | `widget` | `val widget: String? = null` | ## Functions | Function | Signature | | ---------------- | ---------------------------------------------------- | | `getComponents` | `fun getComponents(): List?` | | `getMessageType` | `fun getMessageType(): MessageType?` | ## Related Documentation - [AgentforceAttachment](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/android/agentforce-attachment-android.md) - [AgentforceConversation](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-conversation-android.md) # AgentforceMode `sealed class AgentforceMode` Configuration options for AgentforceClient initialization. ## Types ### EmployeeAgent ```kotlin data class EmployeeAgent( val employeeAgentConfiguration: EmployeeAgentConfiguration, val agentforceConfiguration: AgentforceConfiguration? = null ) : AgentforceMode ``` ### ServiceAgent ```kotlin data class ServiceAgent( val serviceAgentConfiguration: ServiceAgentConfiguration, val agentforceConfiguration: AgentforceConfiguration? = null ) : AgentforceMode ``` ### FullConfig ```kotlin data class FullConfig( val agentforceConfiguration: AgentforceConfiguration ) : AgentforceMode ``` ## Related Documentation - [EmployeeAgentConfiguration](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/employee-agent-configuration-android.md) - [ServiceAgentConfiguration](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/service-agent-configuration-android.md) - [AgentforceConfiguration](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-configuration-android.md) - [AgentforceClient](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-client-android.md) # AgentforceObjectRepresentation `struct AgentforceObjectRepresentation` Represents metadata and structure information for Salesforce objects within the Agentforce SDK. ## Overview This structure provides comprehensive information about Salesforce object types, including their labels, field definitions, theme information, and relationship data. It serves as the foundation for displaying object-related UI components and understanding data structure. ## Declaration ```swift struct AgentforceObjectRepresentation ``` ## Properties | Property | Type | Description | | ----------- | ----------------------------- | ------------------------------------------------------------------- | | objectType | String | The API name of the Salesforce object | | label | String | The singular, human-readable label for the object | | labelPlural | String | The plural, human-readable label for the object | | fields | [String: Field]? | A dictionary of field definitions keyed by field API name | | nameFields | [String]? | An array of field API names that comprise the object's display name | | theme | AgentforceThemeRepresentation | Visual theme information for the object | ## Methods | Method | Signature | Description | | ------ | ------------------------------------------------------------- | ----------------------------------- | | init | `init(objectType:label:labelPlural:fields:nameFields:theme:)` | Creates a new object representation | ## Example Usage ```swift // Create object representation for Account let accountObject = AgentforceObjectRepresentation( objectType: "Account", label: "Account", labelPlural: "Accounts", fields: accountFields, nameFields: ["Name"], theme: AgentforceThemeRepresentation( iconUrl: "https://example.com/account-icon.png", iconColor: "#1B96FF" ) ) // Use in UI components ObjectSelectorView(objects: [accountObject, contactObject]) ``` # AgentforcePageContext `struct AgentforcePageContext` Represents the current page context within a Salesforce application. ## Overview This structure encapsulates information about the user's current location and context within the application, enabling the Agentforce SDK to provide contextually relevant responses and suggestions. ## Declaration ```swift struct AgentforcePageContext ``` ## Properties | Property | Type | Description | | ------------- | ------- | ------------------------------------------------------------------------- | | actionName | String? | The current action being performed on the page | | appName | String? | The name of the current Salesforce application | | objectApiName | String | The API name of the current Salesforce object | | pageName | String? | The name of the current page, if applicable | | pageType | String? | The type of page currently being displayed | | recordId | String? | The unique identifier of the current record, if viewing a specific record | ## Methods | Method | Signature | Description | | ------ | ----------------------------------------- | ------------------------------------------------------------------------ | | init | `init(appName:objectApiName:attributes:)` | Creates a new page context with the specified app and object information | ## Example Usage ```swift // Object home page context let objectContext = AgentforcePageContext( appName: "Sales Cloud", objectApiName: "Account" ) // Record page context let recordContext = AgentforcePageContext( appName: "Sales Cloud", objectApiName: "Account", attributes: [ "recordId": "0018c00003K5dXbAAJ", "actionName": "view" ] ) ``` # AgentforcePageContextProviding `protocol AgentforcePageContextProviding` Protocol for providing page context information to the Agentforce SDK. ## Overview This protocol enables the SDK to understand the current application context, including which Salesforce object, record, or page the user is viewing. This context information is crucial for providing relevant AI responses, suggesting appropriate actions, and maintaining conversation relevance. ## Declaration ```swift protocol AgentforcePageContextProviding ``` ## Properties | Property | Type | Description | | ----------- | ---------------------- | ------------------------------------ | | pageContext | AgentforcePageContext? | The current page context information | ## Example Implementation ```swift class NavigationContextProvider: AgentforcePageContextProviding { var pageContext: AgentforcePageContext? { // Return context based on current navigation state guard let currentObject = navigationManager.currentObject else { return nil } return AgentforcePageContext( appName: "Sales Cloud", objectApiName: currentObject.apiName, attributes: [ "recordId": navigationManager.currentRecordId, "pageType": navigationManager.currentPageType ] ) } } ``` # AgentforceRecordRepresentation `struct AgentforceRecordRepresentation` Represents a Salesforce record with its data, metadata, and display configuration. ## Overview This structure encapsulates a complete Salesforce record including its field values, display configuration, theme information, and field mapping capabilities. It provides the foundation for displaying record information in various UI contexts throughout the Agentforce SDK. ## Declaration ```swift struct AgentforceRecordRepresentation ``` ## Properties | Property | Type | Description | | ------------- | ----------------------------- | -------------------------------------------------------------------- | | recordId | String | The unique 15 or 18-character Salesforce record ID | | objectType | String | The API name of the Salesforce object type | | iconUrl | String? | Optional URL for the record's icon image | | iconColor | String? | Optional color for visual styling of the record | | displayFields | [AgentforceListDisplayColumn] | Configuration for how fields should be displayed in list/table views | | fields | [String: Any] | Complete field data for the record | | fieldmap | [String: String]? | Optional mapping between display names and API field names | ## Methods | Method | Signature | Description | | ---------------------- | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | | init | `init(recordId:objectType:iconUrl:iconColor:displayFields:fields:fieldmap:)` | Creates a new record representation | | getValueForFieldAPI | `func getValueForFieldAPI(_ String) -> Any?` | Retrieves a field value using the Salesforce API field name with relationship traversal support | | getValueForMappedField | `func getValueForMappedField(_ String) -> Any?` | Retrieves a field value using a mapped field name | ## Example Usage ```swift // Access field values directly let accountName = record.getValueForFieldAPI("Name") as? String let ownerName = record.getValueForFieldAPI("Owner.Name") as? String // Use mapped field names let displayName = record.getValueForMappedField("displayName") as? String // Integrate with UI components RecordCardView(record: record) RecordListView(records: [record]) ``` # AgentforceSDKError ```kotlin sealed class AgentforceSDKError : Exception ``` ## Properties | Property | Type | Mutability | Description | | -------- | ---------- | ---------- | ----------------- | | cause | Throwable? | val | Exception cause | | message | String? | val | Exception message | ## Functions | Function | Signature | Description | | ------------------- | -------------------------------------------------------- | ----------- | | addSuppressed | `fun addSuppressed(Throwable): Unit` | | | fillInStackTrace | `open fun fillInStackTrace(): Throwable` | | | getLocalizedMessage | `open fun getLocalizedMessage(): String` | | | getStackTrace | `open fun getStackTrace(): Array` | | | getSuppressed | `fun getSuppressed(): Array` | | | initCause | `open fun initCause(Throwable): Throwable` | | | printStackTrace | `open fun printStackTrace(): Unit` | | | printStackTrace | `open fun printStackTrace(PrintStream): Unit` | | | printStackTrace | `open fun printStackTrace(PrintWriter): Unit` | | | setStackTrace | `open fun setStackTrace(Array): Unit` | | ## Nested Classes - `AgentforceSDKError.NoAgentConfigured` - `AgentforceSDKError.UnableToStartASession` ## Inherited Functions - clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait # AgentforceSDKError ## Overview Errors that can be thrown by the Agentforce SDK during initialization, conversation management, and UI creation. These errors provide specific context about what went wrong and guide developers toward resolution. Handle these errors gracefully in your application to provide a better user experience. ## Declaration ```swift enum AgentforceSDKError: Error ``` ## Properties | Property | Type | Description | | -------------------------- | ---- | ---------------------------------------------------------------------------------------------- | | defaultAgentNotConfigured | case | The default agent for the organization has not been configured in Salesforce | | featureDisabled | case | Feature is disabled | | invalidConversation | case | The provided AgentConversation instance is invalid or was not created by this AgentforceClient | | missingSessionOrViewModel | case | Internal state error where required session or view model components are missing | | noActiveSession | case | No active conversation session available for transcript generation | | transcriptGenerationFailed | case | Server-side transcript generation failed | | unableToStartASession | case | Failed to establish a session with the Agentforce service | # AgentforceService `interface AgentforceService` High-level service interface providing comprehensive Agentforce backend integration and conversation orchestration for Android applications. ## Signature ```kotlin interface AgentforceService ``` ## Description Interface for managing Agentforce conversations, voice interactions, and file uploads. ## Properties | Property | Type | Description | | -------- | ------ | ---------------------------------- | | agentId | String | Agent identifier for conversations | ## Functions | Function | Signature | Description | | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | cancelCurrentStreaming | `open fun cancelCurrentStreaming()` | Cancel current streaming operation | | endAgentforceVoice | `open suspend fun endAgentforceVoice(sessionId: String)` | End realtime voice conversation for the given session. This method disconnects the LiveKit room and cleans up resources | | muteMicrophone | `open suspend fun muteMicrophone(sessionId: String, mute: Boolean)` | Mute or unmute the microphone for the current voice session. This method controls the LiveKit room microphone state | | sendMessageAndStartStreaming | `open suspend fun sendMessageAndStartStreaming(sessionId: String, inputRepresentation: StreamingRequest): ReceiveChannel` | Send message and start streaming response | | setAgentforceVoiceDelegate | `open fun setAgentforceVoiceDelegate(delegate: AgentforceVoiceDelegate?)` | Set the delegate for voice callbacks | | startAgentforceVoice | `open suspend fun startAgentforceVoice(sessionId: String, enableMicrophone: Boolean = true)` | Start realtime voice conversation for the given session. This method handles the join API call and LiveKit room connection internally | | startSession | `open suspend fun startSession(streamingCapabilities: StreamingCapabilities? = null): StartSessionResponse` | Start a new conversation session | | submitFeedback | `open suspend fun submitFeedback(feedbackInput: CopilotFeedbackInput): Boolean` | Submit feedback for the conversation | | uploadFiles | `open suspend fun uploadFiles(sessionId: String?, file: File?, fileName: String, mimeType: String?): MutableList?` | Upload files for the conversation | ## Implementation The primary implementation is provided by `AgentforceServiceImpl`. ```kotlin class AgentforceServiceImpl( val network: Network, val domain: String? = null, val sse: AgentforceServerSentEvents, credentialProvider: AgentforceAuthCredentialProvider, agentforceLogger: Logger?, agentforceInstrumentationHandler: AgentforceInstrumentationHandler?, configurationLocale: Locale?, var agentforceConnectionInfo: AgentforceConnectionInfo?, var agentId: String, context: Context? = null, orgId: String? = null ) : AgentforceService ``` ## Constructor Parameters | Parameter | Type | Description | | -------------------------------- | --------------------------------- | ------------------------------------------- | | network | Network | Network interface for API communication | | domain | String? | Salesforce org domain override | | sse | AgentforceServerSentEvents | Real-time event streaming service | | credentialProvider | AgentforceAuthCredentialProvider | Authentication credential management | | agentforceLogger | Logger? | Logging interface implementation | | agentforceInstrumentationHandler | AgentforceInstrumentationHandler? | Analytics and monitoring integration | | configurationLocale | Locale? | Internationalization configuration | | agentforceConnectionInfo | AgentforceConnectionInfo? | Connection metadata and session information | | agentId | String | Default agent identifier for conversations | | context | Context? | Android application context | | orgId | String? | Organization identifier | ## Inheritors - `AgentforceServiceImpl` - Primary implementation - `MIAWCoreSDKService` - Core SDK service implementation - `MIAWAPIAgentforceService` - MIAW API service implementation ## Related Documentation - [AgentforceClient](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-client-android.md) - Client interface - [AgentforceConfiguration](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-configuration-android.md) - Configuration management - [AgentforceAuthCredentialProvider](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-auth-credential-provider-android.md) - Authentication management # AgentforceThemeControllable ## Overview Protocol defining theme controllability requirements for dynamic color scheme management. This protocol enables theme managers to communicate their color scheme override behavior to the SDK's UI components, ensuring proper visual rendering and theme consistency across all interface elements. ## Declaration ```swift protocol AgentforceThemeControllable ``` ## Properties | Property | Type | Description | | ------------------------------- | ------ | ------------------------------------------------------------------------------- | | `overrideColorSchemeWithSystem` | `Bool` | Indicates whether the theme manager allows system-based color scheme overrides. | # AgentforceThemeManager `interface AgentforceThemeManager` The central theme contract. A theme manager holds a fully resolved theme — both color palettes, typography, shapes, dimensions, shadows, the theme mode, and any icon or display-name overrides — and exposes the values the SDK's UI reads at render time. All theming types live in the package `com.salesforce.android.agentforcesdk.components.theme`. You don't implement this interface. Obtain an instance from one of the factory functions below, or let the SDK build one for you from an `AgentforceThemeOverrides` bag. ## Members | Member | Signature | Description | | ---------------- | ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `colors` | `@Composable fun colors(): AgentforceColorPalette` | The palette for the currently rendering theme mode. Call from a composable. | | `colors` | `fun colors(isDarkMode: Boolean): AgentforceColorPalette` | The palette for the given dark-mode flag. Call from outside composition. A forced `LIGHT` or `DARK` theme mode ignores the flag. | | `typography` | `fun typography(): Typography` | The active text styles. | | `shapes` | `fun shapes(): Shapes` | The active corner shapes. | | `dimensions` | `fun dimensions(): Dimensions` | The active spacing and sizing values. | | `shadows` | `fun shadows(): Shadows` | The active elevation shadows. | | `getIcon` | `fun getIcon(iconType: AgentforceIconType): AgentforceIcon?` | The custom icon for a slot, or `null` when the SDK's built-in drawable applies. | | `getDisplayName` | `fun getDisplayName(displayNameType: AgentforceDisplayNameType): String?` | The custom string for a slot, or `null` when the SDK's built-in string resource applies. An empty override is treated as unset. | | `getThemeMode` | `fun getThemeMode(): AgentforceThemeMode` | The configured mode, returned as-is without resolving `SYSTEM`. | | `isDarkMode` | `@Composable fun isDarkMode(): Boolean` | Whether dark colors are actually rendering, resolving `SYSTEM` against the device setting. | `Typography`, `Shapes`, `Dimensions`, and `Shadows` come from the Salesforce SharedUI design system (`com.salesforce.android.sharedui.theme`). `AgentforceColorPalette` is defined by the SDK. ## Factory functions | Function | Signature | Description | | ------------------------------------- | ------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | `createDefaultAgentforceThemeManager` | `fun createDefaultAgentforceThemeManager(): AgentforceThemeManager` | The out-of-the-box Agentforce theme. Theme mode is `LIGHT`. | | `createCustomAgentforceThemeManager` | see below | A manager with any subset of overrides. Every parameter left `null` falls back to the corresponding Agentforce default. Theme mode defaults to `SYSTEM`. | ```kotlin fun createCustomAgentforceThemeManager( lightColors: AgentforceColorPalette? = null, darkColors: AgentforceColorPalette? = null, shapes: Shapes? = null, dimensions: Dimensions? = null, typography: Typography? = null, shadows: Shadows? = null, themeMode: AgentforceThemeMode? = null, icons: Map? = null, displayNames: Map? = null ): AgentforceThemeManager ``` ## Supplying a theme Pass your theme to `AgentforceConfiguration.Builder.setTheming(...)` using the sealed `AgentforceTheming` type. A theme manager is only one of the three options, and usually not the one you want. | Option | When to use | | ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | `AgentforceTheming.Overrides` (recommended) | Tweak specific tokens and let everything else follow the SDK defaults. Any token you leave out keeps its default. | | `AgentforceTheming.CustomManager` | Own the entire theme end-to-end with a fully resolved manager. | | `AgentforceTheming.Default` | No in-code theme — the SDK default theme is used. | ```kotlin val manager = createCustomAgentforceThemeManager( lightColors = myLight, darkColors = myDark, typography = AgentforceTypography.Default.copyWithFontFamily(brandFont), themeMode = AgentforceThemeMode.SYSTEM, ) val configuration = AgentforceConfiguration.builder(authCredentialProvider) .setApplication(application) .setSalesforceDomain("https://your-instance.salesforce.com") .setTheming(AgentforceTheming.CustomManager(manager)) .build() ``` A resolved manager carries no "unset" signal — every value is already concrete, so there is no way to say "leave this one alone." Prefer `AgentforceTheming.Overrides` unless you genuinely need to own the whole theme. ## Reading theme values in your own components The active manager is published through a Compose `CompositionLocal`, so custom components rendered inside the chat can match the theme. If no manager is provided, the local falls back to `createDefaultAgentforceThemeManager()`, which keeps components working in isolation and in tests. ```kotlin val theme = LocalAgentforceTheme.current val colors = theme.colors() val typography = theme.typography() Text( text = "Hello", style = typography.bodyFontScale1Regular.copy(color = colors.onSurface1), ) ``` ## Migration notes - `AgentforceThemeCreator` and `DefaultAgentforceTheme` are no longer part of the SDK. Use `createDefaultAgentforceThemeManager()` and `createCustomAgentforceThemeManager(...)` instead. - `AgentforceConfiguration.Builder.setThemeManager(...)` and `setThemeOverrides(...)` are deprecated in favor of the single `setTheming(...)` entry point. ## See also - [AgentforceThemeMode](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-theme-mode-android.md) — light, dark, or follow the system. - [Custom Icons](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-icon-type-android.md) — `AgentforceIconType` and `AgentforceIcon`. - [Display Names](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-display-name-type-android.md) — `AgentforceDisplayNameType`. - [AgentforceTypography](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-typography-android.md) — font family and text styles. - [Color Token Reference](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-color-token-reference-android.md) — every customizable color and its light/dark defaults. # AgentforceThemeManager ## Overview Primary theme management interface combining theming capabilities with state observation. This typealias represents the complete theme management contract required by the Agentforce SDK, combining visual theme properties with reactive state management and color scheme control. ## Declaration ```swift typealias AgentforceThemeManager = AgentforceTheme & AgentforceThemeControllable & Observable ``` # AgentforceThemeMode ## Overview Theme mode configuration options that control how the Agentforce SDK adapts to light and dark appearance preferences. These modes provide flexibility for host applications to align the SDK's visual appearance with their own theming strategy while respecting user preferences and system settings. ## Declaration ```swift enum AgentforceThemeMode ``` ## Cases | Case | Description | | -------- | -------------------------------------------------------------- | | `light` | Forces light mode appearance regardless of system preferences. | | `dark` | Forces dark mode appearance regardless of system preferences. | | `system` | Automatically adapts to system-wide appearance preferences. | # AgentforceThemeRepresentation ## Overview Represents visual theme information for Salesforce objects. This structure provides the visual styling information needed to consistently display objects throughout the Agentforce UI. It includes icon resources, color schemes, and fallback options for when primary resources are unavailable. ## Declaration ```swift struct AgentforceThemeRepresentation ``` ## Properties | Property | Type | Description | | --------------- | ---------- | --------------------------------------------------------- | | `iconUrl` | `String?` | The URL for the object's icon image. | | `iconColor` | `String` | The color associated with the object. | | `fallbackImage` | `UIImage?` | A fallback image to use when the icon URL is unavailable. | ## Methods | Method | Signature | Description | | ---------------------------------------- | -------------------------------------------------------------------- | ----------------------------------- | | `init(iconUrl:iconColor:fallbackImage:)` | `init(iconUrl: String?, iconColor: String, fallbackImage: UIImage?)` | Creates a new theme representation. | ## Example Usage ```swift // Standard object theme let accountTheme = AgentforceThemeRepresentation( iconUrl: "https://salesforce.com/icons/standard/account.svg", iconColor: "#1B96FF" ) // Custom object with fallback let customTheme = AgentforceThemeRepresentation( iconUrl: nil, // Custom objects may not have icon URLs iconColor: "#FF6B35", fallbackImage: UIImage(named: "custom-object-icon") ) ``` # AgentforceTypography `object AgentforceTypography : Typography` The Agentforce type scale: a set of 23 text styles covering every text element the SDK draws, extending the Salesforce SharedUI `Typography` base class. `AgentforceTypography.Default` is the ready-made instance — start from it rather than constructing your own. Declared in package `com.salesforce.android.agentforcesdk.components.theme`. ## Properties | Property | Type | Description | | --------------------------- | ----------- | --------------------------------------------------- | | `bodyFontScale1Regular` | `TextStyle` | Body text style at scale 1, regular weight | | `bodyFontScale1Semibold` | `TextStyle` | Body text style at scale 1, semibold weight | | `bodyFontScale2Regular` | `TextStyle` | Body text style at scale 2, regular weight | | `bodyFontScale2Semibold` | `TextStyle` | Body text style at scale 2, semibold weight | | `bodyFontScaleBaseRegular` | `TextStyle` | Base body text style, regular weight | | `bodyFontScaleBaseSemibold` | `TextStyle` | Base body text style, semibold weight | | `bodyFontScaleNeg1Regular` | `TextStyle` | Body text style at negative scale 1, regular weight | | `titlesFontScale3Regular` | `TextStyle` | Title text style at scale 3, regular weight | | `titlesFontScale3Semibold` | `TextStyle` | Title text style at scale 3, semibold weight | | `titlesFontScale4Regular` | `TextStyle` | Title text style at scale 4, regular weight | | `titlesFontScale4Semibold` | `TextStyle` | Title text style at scale 4, semibold weight | | `titlesFontScale5Regular` | `TextStyle` | Title text style at scale 5, regular weight | > This table lists the styles most commonly overridden. The full type scale has 23 styles — see the SDK source or ask the Android team for the complete list before publishing. ## Set a font family for the whole scale `copyWithFontFamily(...)` returns a new `Typography` with every style set to the given font family, leaving weight, size, and line height untouched. ```kotlin import androidx.compose.ui.text.font.FontFamily import com.salesforce.android.agentforcesdk.components.theme.AgentforceTypography val brandFont = FontFamily(/* your Font(...) resources */) val typography = AgentforceTypography.Default.copyWithFontFamily(brandFont) ``` ## Override individual styles To change the weight, size, or line height of specific styles rather than the whole scale, derive from `AgentforceTypography.Default` and apply `mergeWith(...)`, which returns a new `Typography` with only the given styles replaced: ```kotlin import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.sp import com.salesforce.android.agentforcesdk.components.theme.AgentforceTypography val typography = AgentforceTypography.Default.mergeWith( bodyFontScale1Regular = TextStyle(fontSize = 16.sp, lineHeight = 22.sp), ) ``` Pass the result into `createCustomAgentforceThemeManager(typography = typography)`, or set it on `AgentforceThemeOverrides` if you're overriding through `AgentforceTheming.Overrides`. ## See also - [AgentforceThemeManager](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-theme-manager-android.md) — exposes the active typography through `typography()`. - [AgentforceColors](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-colors-android.md) — the matching color palette. - [Android Theming Overview](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/theming-overview-android.md) — how typography fits into the overall theming system. # AgentforceUIAPIFields ## Overview A data structure that represents field information from the UI API in Agentforce conversations. It provides comprehensive field metadata including data types, validation rules, display properties, and relationship information for rendering form fields and data displays in conversation interfaces. ## Declaration ```swift struct AgentforceUIAPIFields ``` ## Properties | Property | Type | Description | | ----------------------- | ------------------------------------ | ---------------------------------------------- | | `apiName` | `String` | The API name of the field | | `calculated` | `Bool` | Whether the field is calculated | | `compound` | `Bool` | Whether the field is compound | | `compoundComponentName` | `String?` | Name of the compound component | | `compoundFieldName` | `String?` | Name of the compound field | | `controllerName` | `String?` | Name of the field controller | | `controllingFields` | `[String]?` | Fields that control this field | | `createable` | `Bool?` | Whether the field can be created | | `custom` | `Bool` | Whether the field is custom | | `dataType` | `String` | The data type of the field | | `externalId` | `Bool?` | Whether the field is an external ID | | `extraTypeInfo` | `String?` | Additional type information | | `filterable` | `Bool` | Whether the field is filterable | | `filteredLookupInfo` | `AgentforceUIAPIFilteredLookupInfo?` | Filtered lookup information | | `highScaleNumber` | `Bool` | Whether the field is a high scale number | | `htmlFormatted` | `Bool` | Whether the field is HTML formatted | | `inlineHelpText` | `String?` | Inline help text for the field | | `label` | `String` | Display label for the field | | `length` | `Int` | Length of the field | | `maskType` | `String?` | Mask type for the field | | `nameField` | `Bool` | Whether the field is a name field | | `polymorphicForeignKey` | `Bool` | Whether the field is a polymorphic foreign key | | `precision` | `Int` | Precision of the field | | `reference` | `Bool` | Whether the field is a reference | | `referenceTargetField` | `String?` | Target field for references | | `referenceToInfos` | `[AgentforceUIAPIReferenceToInfo]?` | Reference information | | `relationshipName` | `String?` | Name of the relationship | | `required` | `Bool` | Whether the field is required | | `searchPrefilterable` | `Bool` | Whether the field is search prefilterable | | `scale` | `Int` | Scale of the field | | `sortable` | `Bool` | Whether the field is sortable | | `unique` | `Bool` | Whether the field is unique | | `updateable` | `Bool` | Whether the field is updateable | ## Methods | Method | Signature | Description | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | | `init` | `init(apiName:calculated:compound:compoundComponentName:compoundFieldName:controllerName:controllingFields:createable:custom:dataType:externalId:extraTypeInfo:filterable:filteredLookupInfo:highScaleNumber:htmlFormatted:inlineHelpText:label:length:maskType:nameField:polymorphicForeignKey:precision:reference:referenceTargetField:referenceToInfos:relationshipName:required:searchPrefilterable:scale:sortable:unique:updateable:)` | Initializes a new field with all properties | | `init(from:)` | `init(from: Decoder) throws` | Initializes from a decoder for JSON deserialization | # AgentforceUIApiFieldValues ## Overview A data structure that represents field values from the UI API in Agentforce conversations. It provides a structured way to represent field values with both display and raw value information. ## Declaration ```swift struct AgentforceUIAPIFieldValues ``` ## Properties | Property | Type | Description | | -------------- | --------- | ----------------------------------------- | | `displayValue` | `String?` | The formatted display value for the field | | `value` | `Any?` | The raw value of the field | ## Methods | Method | Signature | Description | | --------------------------- | ------------------------------------------------------ | ----------------------------------------------------------- | | `init(displayValue:value:)` | `init(displayValue: String? = nil, value: Any? = nil)` | Creates a new instance with optional display and raw values | # AgentforceUIAPIObjectInfo ## Overview A data structure that represents object information from the UI API in Agentforce conversations. It provides comprehensive object metadata including field definitions, relationship information, layout capabilities, and display properties for rendering object information in conversation interfaces. ## Declaration ```swift struct AgentforceUIAPIObjectInfo ``` ## Properties | Property | Type | Description | | ----------------------- | ----------------------------------------- | ------------------------------------------ | | `apiName` | `String` | The API name of the object | | `associateEntityType` | `String?` | Associated entity type | | `associateParentEntity` | `String?` | Associated parent entity | | `childRelationships` | `[AgentforceUIAPIChildRelationship]` | Child relationships | | `compactLayoutable` | `Bool?` | Whether the object supports compact layout | | `createable` | `Bool?` | Whether the object can be created | | `custom` | `Bool` | Whether the object is custom | | `defaultRecordTypeId` | `String?` | Default record type ID | | `deletable` | `Bool` | Whether the object can be deleted | | `fields` | `[String: AgentforceUIAPIFields]` | Field definitions | | `keyPrefix` | `String?` | Key prefix for the object | | `label` | `String` | Display label for the object | | `labelPlural` | `String` | Plural display label | | `layoutable` | `Bool` | Whether the object supports layout | | `mruEnabled` | `Bool` | Whether most recently used is enabled | | `nameFields` | `[String]` | Name fields for the object | | `queryable` | `Bool` | Whether the object is queryable | | `recordTypeInfos` | `[String: AgentforceUIAPIRecordTypeInfo]` | Record type information | | `searchable` | `Bool` | Whether the object is searchable | | `searchLayoutable` | `Bool?` | Whether the object supports search layout | | `themeInfo` | `AgentforceUIAPIThemeInfo?` | Theme information | | `updateable` | `Bool` | Whether the object can be updated | ## Methods | Method | Signature | Description | | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | | `init` | `init(apiName:associateEntityType:associateParentEntity:childRelationships:compactLayoutable:createable:custom:defaultRecordTypeId:deletable:fields:keyPrefix:label:labelPlural:layoutable:mruEnabled:nameFields:queryable:recordTypeInfos:searchable:searchLayoutable:themeInfo:updateable:)` | Initializes a new object info with all properties | | `init(from:)` | `init(from: Decoder) throws` | Initializes from a decoder for JSON deserialization | # AgentforceUIApiRecord ## Overview A data structure that represents UI API record information in Agentforce conversations. It provides comprehensive record metadata including fields, relationships, and system information for displaying records in conversation interfaces. ## Declaration ```swift struct AgentforceUIAPIRecord ``` ## Properties | Property | Type | Description | | -------------------- | -------------------------------------------- | ------------------------------------------------------------ | | `apiName` | `String` | The API name of the record | | `childRelationships` | `[String : AgentforceUIAPIRecordCollection]` | Dictionary of child relationship names to record collections | | `eTag` | `String` | Entity tag for the record | | `fields` | `[String : AgentforceUIAPIFieldValues]` | Dictionary of field names to field values | | `id` | `String` | The unique identifier of the record | | `lastModifiedById` | `String?` | ID of the user who last modified the record | | `lastModifiedDate` | `String?` | Date when the record was last modified | | `recordTypeId` | `String?` | ID of the record type | | `recordTypeInfo` | `AgentforceUIAPIRecordTypeInfo?` | Information about the record type | | `systemModstamp` | `String?` | System modification timestamp | | `weakEtag` | `Int64` | Weak entity tag for the record | ## Methods | Method | Signature | Description | | ---------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | | `init(apiName:childRelationships:eTag:weakEtag:fields:id:lastModifiedById:lastModifiedDate:recordTypeId:recordTypeInfo:systemModstamp:)` | `init(apiName: String, childRelationships: [String : AgentforceUIAPIRecordCollection], eTag: String, weakEtag: Int64, fields: [String : AgentforceUIAPIFieldValues], id: String, lastModifiedById: String?, lastModifiedDate: String?, recordTypeId: String?, recordTypeInfo: AgentforceUIAPIRecordTypeInfo?, systemModstamp: String?)` | Creates a new record with all metadata and field information | | `init(from:)` | `init(from decoder: Decoder) throws` | Creates a new instance from a decoder (inherited from Decodable) | # AgentforceUIApiRecordCollection ## Overview A data structure that represents a collection of UI API records in Agentforce conversations. It provides pagination support and metadata for managing multiple records from the UI API. ## Declaration ```swift struct AgentforceUIAPIRecordCollection ``` ## Properties | Property | Type | Description | | ------------------- | ---------------------------------- | --------------------------------------------- | | `count` | `Int` | The total number of records in the collection | | `currentPageToken` | `String` | Token for the current page | | `currentPageUrl` | `String` | URL for the current page | | `nextPageToken` | `String?` | Token for the next page, if available | | `nextPageUrl` | `String?` | URL for the next page, if available | | `previousPageToken` | `String?` | Token for the previous page, if available | | `previousPageUrl` | `String?` | URL for the previous page, if available | | `records` | `[AgentforceRecordRepresentation]` | Array of record representations | ## Methods | Method | Signature | Description | | ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | | `init(count:currentPageToken:currentPageUrl:nextPageToken:nextPageUrl:previousPageToken:previousPageUrl:records:)` | `init(count: Int, currentPageToken: String, currentPageUrl: String, nextPageToken: String? = nil, nextPageUrl: String? = nil, previousPageToken: String? = nil, previousPageUrl: String? = nil, records: [AgentforceRecordRepresentation])` | Creates a new record collection with pagination metadata and records | | `init(from:)` | `init(from decoder: Decoder) throws` | Creates a new instance from a decoder (inherited from Decodable) | # AgentforceUIApiRecordTypeInfo ## Overview A data structure that represents record type information from the UI API in Agentforce conversations. It provides metadata about record types including availability, mapping, and identification information. ## Declaration ```swift struct AgentforceUIAPIRecordTypeInfo ``` ## Properties | Property | Type | Description | | -------------------------- | --------- | ----------------------------------------------- | | `available` | `Bool` | Whether the record type is available | | `defaultRecordTypeMapping` | `Bool` | Whether this is the default record type mapping | | `master` | `Bool` | Whether this is the master record type | | `name` | `String` | The name of the record type | | `recordTypeId` | `String?` | The unique identifier of the record type | ## Methods | Method | Signature | Description | | -------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | | `init(available:defaultRecordTypeMapping:master:name:recordTypeId:)` | `init(available: Bool, defaultRecordTypeMapping: Bool, master: Bool, name: String, recordTypeId: String? = nil)` | Creates a new record type info with metadata | | `init(from:)` | `init(from decoder: Decoder) throws` | Creates a new instance from a decoder (inherited from Decodable) | # AgentforceUIDelegate ## Overview Protocol that enables customization of user interactions and conversation behavior within Agentforce UI components. Implement this protocol to intercept and modify utterances before sending, receive notifications about conversation events, and handle agent switching scenarios. ## Declaration ```swift protocol AgentforceUIDelegate ``` ## Methods | Method | Signature | Description | | ------------------------------ | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | `modifyUtteranceBeforeSending` | `func modifyUtteranceBeforeSending(_ utterance: AgentforceUtterance) async -> AgentforceUtterance` | Allows modification of user utterances before they are sent to the agent. Returns the original utterance unchanged by default. | | `didSendUtterance` | `func didSendUtterance(_ utterance: AgentforceUtterance)` | Called after an utterance has been successfully sent to the agent. No-op by default. | | `userDidSwitchAgents` | `func userDidSwitchAgents(newConversation: AgentConversation)` | Called when the user switches to a different agent during a conversation. No-op by default. | | `userInitiatedVoice` | `func userInitiatedVoice(for conversation: AgentConversation)` | Called when the user initiates a voice interaction for a conversation. No-op by default. | ## Implementation Patterns ```swift class MyUIDelegate: AgentforceUIDelegate { // Modify utterances before sending func modifyUtteranceBeforeSending(_ utterance: AgentforceUtterance) async -> AgentforceUtterance { // Add user context to the message var modifiedUtterance = utterance modifiedUtterance.context = [ "userId": UserSession.current.userId, "timestamp": Date().iso8601 ] return modifiedUtterance } } ``` ```swift class AnalyticsUIDelegate: AgentforceUIDelegate { // Track when messages are sent func didSendUtterance(_ utterance: AgentforceUtterance) { Analytics.track("message_sent", properties: [ "message_length": utterance.text.count, "has_attachments": !utterance.attachments.isEmpty ]) } } ``` ```swift class AgentSwitchDelegate: AgentforceUIDelegate { func userDidSwitchAgents(newConversation: AgentConversation) { NotificationCenter.default.post( name: .agentSwitched, object: nil, userInfo: ["conversation": newConversation] ) } } ``` ## Switch From Chat View to Voice View Use `userInitiatedVoice` to present your own instance of `AgentforceVoiceView`. `userInitiatedVoice` is called when a user taps the button that opens the voice view from the chat view. This sample code demonstrates rerendering the view when a user selects the voice option. ```swift enum PresentationState { case none case chat case voice } struct MyCustomView: View { @State var presentationState: PresentationState = .none var body: some View { // Show chatView and voiceView based on presentationState } } extension MyCustomView: AgentforceUIDelegate { func userInitiatedVoice(for conversation: any AgentConversation) { presentationState = .voice } } ``` # AgentforceVoiceView ## Overview A SwiftUI view that provides the user interface for voice interaction with Agentforce. Displays connection status, animated visual feedback, and control buttons for real-time voice conversations with AI agents. ## Declaration ```swift @MainActor struct AgentforceVoiceView ``` ## Properties | Property | Type | Description | | -------- | ----------- | ------------------------------------------- | | `body` | `some View` | The main view content (inherited from View) | ## Methods | Method | Signature | Description | | --------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | _Inherited from View_ | _All View protocol methods_ | Inherits all standard SwiftUI View methods and modifiers. See [View (_Apple Developer_)](https://developer.apple.com/documentation/swiftui/view) | # Android Analytics Overview Analytics and instrumentation for the Agentforce Android SDK. ## Analytics Classes - **[AgentforceInstrumentationHandler](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-instrumentation-handler-android.md)** - Analytics event handling - **[AgentforceInstrumentationEvent](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-instrumentation-event-android.md)** - Event data structures ## Analytics Features ### Event Tracking - **User Interactions**: Button clicks, form submissions, and navigation - **Conversation Events**: Message sending, receiving, and conversation state changes - **Performance Metrics**: Response times, error rates, and system performance - **Custom Events**: Application-specific analytics and user behavior ### Data Collection - **Event Properties**: Structured data for each analytics event - **User Context**: User identification and session information - **System Context**: Device information and application state - **Privacy Controls**: Data collection preferences and consent management ## Implementation ### Event Handler ```kotlin class MyAnalyticsHandler : AgentforceInstrumentationHandler { override fun trackEvent(event: AgentforceInstrumentationEvent) { // Send event to analytics service } } ``` ### Event Types - **User Events**: User interactions and behavior - **System Events**: Application and SDK performance - **Error Events**: Error tracking and debugging - **Business Events**: Application-specific metrics ## Next Steps - **Configuration**: See [Configuration Overview](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/configuration-overview-android.md) for setup - **UI Components**: See [Android UI Components](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ui-components-android.md) for component analytics - **Integration**: See [Android Development](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/development-android.md) for architecture patterns # Android Architecture & Integration Core architecture and services for Android development with the Agentforce Mobile SDK. ## Available Services Implement these core services for integration and data management: - **[AgentforceAPI](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-api-android.md)** - Network service layer for API communication - **[AgentforceService](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-service-android.md)** - Backend integration and business logic - **[BotsAPI](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/bots-api-android.md)** - Conversation API client for agent interactions ## Architecture Overview The Android SDK implements service-oriented architecture with coroutines for async operations and follows modern Android development patterns. It uses Jetpack Compose for declarative UI development and integrates with Material Design principles. # Android Architecture Integration Technical reference for Android platform integration patterns and requirements. ## System Requirements | Requirement | Version | | -------------- | ---------------- | | Android API | 29+ (Android 10) | | Kotlin | 1.9.22+ | | Android Studio | Meerkat+ | | Compose BOM | 2023.10.01+ | ## Architecture Patterns | Pattern | Description | | ----------------------------- | --------------------------------------------------------- | | Service-Oriented Architecture | Clean separation of concerns with network and data layers | | Coroutines Support | Async operations with proper lifecycle management | | Jetpack Compose UI | Modern declarative UI components with Material Design | | Material Design Integration | Consistent theming and styling with Android design system | ## Core Integration Points Essential API signatures and patterns for Android integration. ### API Initialization ```kotlin AgentforceAPI( network: NetworkProvider, credentialProvider: CredentialProvider ) ``` ### Conversation Creation ```kotlin AgentforceConversation( agentId: String, configuration: AgentforceConfiguration ) ``` ### Compose UI Integration ```kotlin @Composable fun AgentforceChatView( conversation: AgentforceConversation, modifier: Modifier = Modifier ) ``` ## Component Reference Complete reference of Android components and services. ### UI Components | Component | Type | Description | | ------------------------------------------------------ | ---------- | -------------------------------------- | | [AgentforceComponent](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-component-android.md) | Composable | Base component system for UI rendering | | [ChatResponseButton](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/chat-response-button-android.md) | Composable | Interactive response buttons | | [RecordSelector](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/record-selector-android.md) | Composable | Salesforce record selection interface | ### Core Services | Service | Purpose | | -------------------------------------------------- | ---------------------------------------------- | | [AgentforceAPI](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-api-android.md) | Network service layer for API communication | | [AgentforceService](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-service-android.md) | Backend integration and business logic | | [BotsAPI](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/bots-api-android.md) | Conversation API client for agent interactions | ## Related Documentation - [UI Components Implementation Guide](/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-ui-components.html) - Usage patterns and examples - [Android Integration Guidelines](/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-android.html) - Complete setup instructions - [Architecture Guide](/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-architecture.html) - Design patterns and concepts # Android Authentication Overview Authentication interfaces and credential management for the Agentforce Android SDK. ## Authentication Classes - **[AgentforceAuthCredentialProvider](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-auth-credential-provider-android.md)** - Credential provider interface - **[AgentforceAuthCredentials](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-auth-credentials-android.md)** - Authentication credentials structure ## Authentication Types ### OAuth Authentication - **Access Token**: OAuth 2.0 access token for API authentication - **Refresh Token**: Token for refreshing expired access tokens - **Expiration**: Token expiration time and refresh logic ### Org JWT Authentication - **JWT Token**: JSON Web Token for organization authentication - **Claims**: User and organization claims within the JWT - **Validation**: Token validation and security checks ## Implementation Patterns ### Credential Provider ```kotlin class MyCredentialProvider : AgentforceAuthCredentialProvider { override fun getCredentials(): AgentforceAuthCredentials { // Return current authentication credentials } } ``` ### Credential Management - **Token Refresh**: Automatic token refresh when expired - **Security**: Secure storage and transmission of credentials - **Validation**: Credential validation before API calls ## Next Steps - **Configuration**: See [Configuration Overview](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/configuration-overview-android.md) for setup - **Data Models**: See [Data Models Overview](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/data-models-overview-android.md) for message handling - **Integration**: See [Android Development](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/development-android.md) for architecture patterns # Android Configuration Overview Configuration classes and patterns for the Agentforce Android SDK. ## Configuration Classes - **[AgentforceMode](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-mode-android.md)** - Agent type configuration - **[AgentforceConfiguration](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-configuration-android.md)** - Main configuration class - **[EmployeeAgentConfiguration](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/employee-agent-configuration-android.md)** - Employee agent settings - **[ServiceAgentConfiguration](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/service-agent-configuration-android.md)** - Service agent settings - **[AgentforceClient](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-client-android.md)** - Client initialization - **[AgentforceConversation](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-conversation-android.md)** - Conversation management - **[AgentforceContextManager](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-context-manager-android.md)** - Context management ## Quick Start 1. **Choose Agent Type**: Select between EmployeeAgent, ServiceAgent, or FullConfig 2. **Configure Settings**: Set up authentication, UI preferences, and feature flags 3. **Initialize Client**: Create and configure the AgentforceClient 4. **Start Conversation**: Begin user interactions with the configured agent ## Next Steps - **Authentication**: See [Authentication Overview](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/authentication-overview-android.md) for credential setup - **UI Components**: See [Android UI Components](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ui-components-android.md) for interface building - **Integration**: See [Android Development](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/development-android.md) for architecture patterns # Android Data Models Overview Data structures and models for the Agentforce Android SDK. ## Data Model Classes - **[AgentforceMessage](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/android/agentforce-message-android.md)** - Message structure and handling - **[AgentforceAttachment](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/android/agentforce-attachment-android.md)** - File attachment support ## Message Types ### Text Messages - **Content**: Message text content and formatting - **Metadata**: Timestamps, sender information, and message state - **Formatting**: Rich text support and markdown rendering ### Attachment Messages - **File Types**: Support for images, documents, and media files - **Upload**: File upload and processing - **Display**: Attachment rendering in UI components ## Data Flow ### Message Creation 1. **User Input**: Capture user input through UI components 2. **Message Construction**: Create AgentforceMessage objects 3. **Validation**: Validate message content and attachments 4. **Transmission**: Send messages through the SDK ### Message Processing 1. **Reception**: Receive messages from the agent 2. **Parsing**: Parse message content and attachments 3. **Rendering**: Display messages in UI components 4. **State Management**: Update conversation state ## Next Steps - **UI Components**: See [Android UI Components](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ui-components-android.md) for message display - **Configuration**: See [Configuration Overview](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/configuration-overview-android.md) for setup - **Integration**: See [Android Development](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/development-android.md) for architecture patterns # Android Error Handling Overview Error handling classes and patterns for the Agentforce Android SDK. ## Error Classes - **[AgentforceSDKError](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-sdk-error-android.md)** - SDK error types and exceptions ## Error Types The Android SDK provides specific error types for different failure scenarios: - **NoAgentConfigured** - When no agent is properly configured - **UnableToStartASession** - When session initialization fails ## Usage Patterns Error handling in the Android SDK follows standard Java exception patterns: ```kotlin try { val client = AgentforceClient() // SDK operations } catch (error: AgentforceSDKError) { when (error) { is AgentforceSDKError.NoAgentConfigured -> { // Handle configuration error } is AgentforceSDKError.UnableToStartASession -> { // Handle session error } } } ``` ## Related Documentation - [AgentforceClient](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-client-android.md) - Main client class that may throw errors - [AgentforceConversation](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-conversation-android.md) - Conversation management with error handling # Android Integration Guide This section gives integration guidelines for building an Android app with the Agentforce Mobile SDK. For the quick start experience, see [Android Quick Start](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-android-quick-start.md). # Android Quick Start Guide Get up and running quickly with the Agentforce Mobile SDK for Android using these instructions. ## Before You Begin Ensure you have: - A Salesforce org with Agentforce enabled - An agent configured in your org (Employee Agent or Service Agent) - The required values from your Salesforce org depending on agent type For detailed setup instructions, see [Before You Begin](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/agentforce-mobile-sdk-before-you-begin.md). ### For Service Agent You need these values from your Salesforce org: - **Service API URL**: Setup > Embedded Service Deployments > your deployment > Settings - **Organization ID**: Setup > Company Information - **ES Developer Name**: Setup > Embedded Service Deployments > Developer Name ### For Employee Agent You need these values from your Salesforce org: - **Agent ID**: From the Agent Details page URL (the 18-character ID at the end) - **User ID**: From the user profile. See [Find the Salesforce ID for a User](https://help.salesforce.com/s/articleView?id=000381643&type=1). - **Salesforce Domain**: Setup > My Domain > Current My Domain URL ## 1. Add Dependencies Add the Agentforce SDK to your project. ```kotlin // settings.gradle.kts dependencyResolutionManagement { repositories { google() mavenCentral() maven { url = uri("https://jitpack.io") } maven { url = uri("https://opensource.salesforce.com/AgentforceMobileSDK-Android/agentforce-sdk-repository") } maven { url = uri("https://s3.amazonaws.com/inapp.salesforce.com/public/android") } maven { url = uri("https://s3.amazonaws.com/salesforce-async-messaging-experimental/public/android") } } } // build.gradle.kts plugins { id("com.android.application") id("kotlin-android") id("kotlin-kapt") id("kotlinx-serialization") id("org.jetbrains.kotlin.plugin.compose") } // app/build.gradle.kts android { compileOptions { isCoreLibraryDesugaringEnabled = true } } dependencies { // Agentforce SDK Dependencies api("com.salesforce.android.agentforcesdk:agentforce-sdk:14.97.1") coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3") } ``` To learn more, see [Install the Android SDK](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-android-install.md). ## 2. Add Required Permissions See [Android Requirements](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-android-requirements.md). ## 3. Implement Credential Provider To use the SDK, be sure to import the Agentforce SDK packages. ```swift import com.salesforce.android.agentforceservice.* ``` Create a credential provider using one of the supported authentication methods. ```kotlin class MyAppCredentialProvider : AgentforceAuthCredentialProvider { override fun getAuthCredentials(): AgentforceAuthCredentials { return AgentforceAuthCredentials.OAuth( authToken = "YOUR_AUTH_TOKEN", orgId = "YOUR_ORG_ID", userId = "YOUR_USER_ID" ) } } ``` ```kotlin class MyAppCredentialProvider : AgentforceAuthCredentialProvider { override fun getAuthCredentials(): AgentforceAuthCredentials { return AgentforceAuthCredentials.OrgJWT(orgJWT = "YOUR_ORG_JWT") } } ``` ```kotlin class MyAppCredentialProvider : AgentforceAuthCredentialProvider { override fun getAuthCredentials(): AgentforceAuthCredentials { return AgentforceAuthCredentials.Guest(url = "YOUR_GUEST_URL") } } ``` To learn more, see [Integrate Agentforce SDK](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-android-integration.md). ## 4. Configure Chat Configure your chat object for Employee agent or Service agent. **tip:** For guidance on gathering information for the agent configuration object, see [Agent Type Setup](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/agentforce-mobile-sdk-before-you-begin.md#agent-type) in Before You Begin. ```kotlin // Configure an Employee agent val configuration = AgentforceConfiguration.builder( authCredentialProvider = myAuthCredentialProvider ) .setApplication(application) .setSalesforceDomain("https://your-domain.my.salesforce.com") .setAgentId("YOUR_AGENT_ID") .setThemeManager(createCustomAgentforceThemeManager(themeMode = AgentforceThemeMode.SYSTEM)) .setNetwork(myNetworkProvider) .setLogger(myLogger) .setNavigation(myNavigation) .build() // Set mode for Employee agent val agentforceMode = AgentforceMode.FullConfig(configuration) // Create client agentforceClient?.init( authCredentialProvider = configuration.authCredentialProvider, agentforceMode = agentforceMode, application = application ) ``` ```kotlin // Configure a Service agent val serviceAgentConfig = ServiceAgentConfiguration.builder( serviceApiURL = "https://your-service-api-url.com", organizationId = "YOUR_ORG_ID", esDeveloperName = "YOUR_CHAT_DEVELOPER_NAME", authorizationContext = AuthorizationContext( authorizationMethod = AuthorizationMethod.UNVERIFIED ) ).build() val agentforceMode = AgentforceMode.ServiceAgent( serviceAgentConfiguration = serviceAgentConfig, agentforceConfiguration = configuration ) // Create client agentforceClient?.init( authCredentialProvider = configuration.authCredentialProvider, agentforceMode = agentforceMode, application = application ) ``` To learn more, see [Integrate Agentforce SDK](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-android-integration.md). ## 5. Start and Present Chat Start the chat conversation. ```kotlin // Start conversation val conversation = agentforceClient.startAgentforceConversation() ``` And add the UI component. ```kotlin @Composable fun MyChatScreen( agentforceClient: AgentforceClient, conversation: AgentforceConversation, onClose: () -> Unit ) { agentforceClient.AgentforceConversationContainer( conversation = conversation, onClose = onClose ) } ``` To learn more, see [Integrate Agentforce SDK](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-android-integration.md). ## Next Steps - **Customization**: See [Branding and Theming](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-android-branding-theming.md) for visual customization - **Full Integration**: See [Integration Guide](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-android-integration-overview.md) for complete implementation # Android Theming Overview Theming system and visual customization for the Agentforce Android SDK. The SDK lets you customize colors, typography, icons, on-screen text, and light/dark behavior for every UI component in the full-UI chat experience. All theming types live in the package `com.salesforce.android.agentforcesdk.components.theme`. ## Quick start Supply a theme once, through `AgentforceConfiguration.Builder.setTheming(...)`. List only the tokens you want to change; everything else keeps its SDK default. ```kotlin import androidx.compose.ui.graphics.Color import com.salesforce.android.agentforcesdk.components.theme.AgentforceColorToken import com.salesforce.android.agentforcesdk.components.theme.AgentforceThemeMode import com.salesforce.android.agentforcesdk.components.theme.AgentforceThemeOverrides import com.salesforce.android.agentforcesdk.components.theme.AgentforceTheming val theming = AgentforceTheming.Overrides( AgentforceThemeOverrides( lightColors = mapOf(AgentforceColorToken.Accent1 to Color(0xFF0170CB)), darkColors = mapOf(AgentforceColorToken.Accent1 to Color(0xFF008AF7)), themeMode = AgentforceThemeMode.SYSTEM, ) ) val configuration = AgentforceConfiguration.builder(authCredentialProvider) .setApplication(application) .setSalesforceDomain("https://your-instance.salesforce.com") .setTheming(theming) .build() ``` ## What you can customize | Area | Type(s) | Scope | | -------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------- | | Colors | `AgentforceColorPalette`, `AgentforceColorToken` | 271 tokens — 47 foundation plus 224 component-level across 50 component groups. | | Font family | `AgentforceTypography.copyWithFontFamily(...)` | Applies your font to all 23 text styles at once. | | Per-style typography | `Typography.mergeWith(...)` | Adjust the weight, size, or line height of individual styles. | | Icons | `AgentforceIconType`, `AgentforceIcon` | 23 replaceable icons, with optional separate light and dark variants. | | Display-name strings | `AgentforceDisplayNameType` | 45 user-visible strings such as titles, hints, and button labels. | | Theme mode | `AgentforceThemeMode` | `SYSTEM`, `LIGHT`, or `DARK`. | Shapes, dimensions, and shadows come from the Salesforce SharedUI design system and can also be overridden through `AgentforceThemeOverrides` or `createCustomAgentforceThemeManager(...)`, using the SharedUI `Shapes`, `Dimensions`, and `Shadows` types. ## How the pieces fit together 1. You describe your theme with `AgentforceThemeOverrides` (a sparse bag of just the tokens you want to change) or with a fully resolved `AgentforceThemeManager`. 2. You pass it to `setTheming(...)` using the sealed `AgentforceTheming` type: `Default`, `Overrides`, or `CustomManager`. 3. The SDK resolves that into an `AgentforceThemeManager` and publishes it through the `LocalAgentforceTheme` Compose `CompositionLocal`. 4. Every component reads its values from that local, so the UI recomposes when the theme or the device's light/dark setting changes. Prefer `AgentforceTheming.Overrides`. A fully resolved manager carries no "unset" signal, so there is no way to say "leave this one alone." ## Reference pages | Page | What it covers | | --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | [Theming guide](/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-android-branding-theming.html) | End-to-end walkthrough: supplying a theme, then customizing colors, typography, icons, strings, and theme mode. | | [AgentforceThemeManager](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-theme-manager-android.md) | The theme contract, the factory functions, and reading theme values in your own components. | | [AgentforceColors](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-colors-android.md) | The palette class, the default light and dark palettes, the `AgentforceColorToken` enum, and `withOverrides(...)`. | | [Color Token Reference](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-color-token-reference-android.md) | Every one of the 271 color tokens, with its fallback and its default light and dark value. | | [AgentforceTypography](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-typography-android.md) | The 23 text styles with their weights, sizes, and line heights, plus `copyWithFontFamily(...)`. | | [Custom Icons](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-icon-type-android.md) | Every replaceable icon, its default drawable, and which color token tints it. | | [Display Names](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-display-name-type-android.md) | Every customizable string, its default text, and where it appears. | | [Theme Mode](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-theme-mode-android.md) | Light, dark, or follow the system, and how each mode resolves. | | [Server-Driven Branding](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/server-driven-branding-android.md) | How an org can supply a theme centrally, and how it merges with your in-code theme. | ## Renamed and removed types If you're coming from older documentation: | Old name | Use instead | | -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | `AgentforceColors` | Never a type — it was the file name. The types are `AgentforceColorPalette`, `AgentforceLightColors`, `AgentforceDarkColors`, and `AgentforceColorToken`. | | `AgentforceThemeCreator` | `createDefaultAgentforceThemeManager()` or `createCustomAgentforceThemeManager(...)`. | | `DefaultAgentforceTheme` | `createDefaultAgentforceThemeManager()`. | | `Typography` (base class) | `AgentforceTypography`, with `Typography.mergeWith(...)` for per-style overrides. | | `SalesforceTextFontScale` | Internal to the SDK. Font scaling now follows the device's font-scale setting automatically. | | `AgentforceSpacing`, `Spacing`, `Spacing (Styles)` | Internal to the SDK. Override spacing through the SharedUI `Dimensions` type instead. | | `setThemeManager(...)` / `setThemeOverrides(...)` | `setTheming(...)` with `AgentforceTheming`. | `AgentforceThemeManager` is an interface with read-only accessors. You can't construct it directly and there are no setter methods — build one with `createCustomAgentforceThemeManager(...)`, which takes every theme property as a defaulted parameter. ## See also - **UI Components**: See [Android UI Components](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ui-components-android.md) for component theming. - **Configuration**: See [Configuration Overview](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/configuration-overview-android.md) for setup. - **Integration**: See [Android Development](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/development-android.md) for architecture patterns. # Android UI Components Native Jetpack Compose components for building conversational interfaces with the Agentforce Mobile SDK. ## Available Components Build conversational interfaces with these native Compose components: - **[AgentforceComponent](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-component-android.md)** - Base component system for UI rendering and interaction - **[ChatResponseButton](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/chat-response-button-android.md)** - Interactive response buttons and action handling - **[RecordSelector](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/record-selector-android.md)** - Salesforce record selection and display components ## Integration All UI components follow Material Design principles and integrate with the Android theming system for consistent styling and customization. # Apex Code Example: Custom Apex Action for Complex Queries This example walks you through the end-to-end steps to implement an agent that handles complex customer questions using a custom Apex action. ## Scenario in This Example This example covers end-to-end implementation of a customer service agent that can handle complex queries about product inventory. Using Apex, we will create a custom action that converts a customer question with multiple parts into an actionable SOQL query. By setting up each component individually, you’ll gain a thorough understanding of their configuration and how they fit into the Agentforce solution stack. You’re welcome to follow along with the instructions in a Salesforce Developer org. Note that your results may vary. In this example, we'll use Salesforce CLI to import existing product and price data from .csv files into Salesforce standard objects Product2 and PriceBook. Then, we’ll create a custom Apex class to dynamically query our products inventory based on inputs passed by our agent. Finally, we’ll build an agent, subagent, and action to call the custom Apex class when needed. ## Step 1: Set Up a Salesforce Developer Edition Org To sign up, click [here](https://www.salesforce.com/form/developer-signup/?d=pb). **note:** If you’d prefer to use a different Salesforce org, verify that it offers comparable functionality: Einstein is enabled, Agentforce is enabled, and it’s OK for you to add cases. Note that your user permissions and other org settings can affect your ability to complete all the steps in this example. **note:** If you're following along with the instructions and your org runs into unexpected issues, try refreshing your browser window. You can also try going back and repeating previous instructions. 1. Log into the Salesforce Developer Edition org. 2. From **Setup**, in the Quick Find box, enter `einstein setup`, and then select **Einstein Setup** and **Turn on Einstein**. ![Einstein Setup Search](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-1.png) 3. Search for **Agentforce Agents** and open it. 4. Turn on **Agentforce**. ![Agentforce Setup Search](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-2.png) ## Step 2: Import Your Data Our custom Apex class queries structured data inside our org. That means we need to get our data cleaned, organized, and inside the appropriate Salesforce objects. Here is the sample data we are using for this example: [Link](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-demo-data.csv). This .csv file contains 100 furniture items with a Name, Description, SKU, Price, Color, and Weight. ### Create Custom Fields We’re going to store most of our data in the Product2 object. Let’s start by creating custom fields for Color and Weight, since they aren’t included by default. 1. From Setup, click **Object Manager**, then scroll down to **Product** (API name **Product2**). ![Object Manager Search](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-3.png) 2. Click **Fields & Relationships**, then click **New**. ![Fields and Relationships](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-4.png) 3. Create the Color custom field with the following settings, then save the field. 1. **Field Type**: Picklist 2. **Label**: Color 3. **Values**: Black, White, Brown, Grey, Navy, Beige, Green, Red, Oak, Walnut 4. On the field-level security screen, check **Visible** for your profile 4. Create the Weight (kg) custom field with the following settings, then save the field. 1. **Field Type**: Number 2. **Label**: Weight (kg) 3. **Length**: 16 4. **Decimal Places**: 2 5. On the field-level security screen, check **Visible** for your profile ### Import Product2 Data with Salesforce CLI Because we’re importing inventory data to the Product2 object, we’re restricted to using [Salesforce CLI](https://developer.salesforce.com/tools/salesforcecli) or [Salesforce Data Loader](https://developer.salesforce.com/tools/data-loader). You can also create the data entries manually, but that method is too time consuming for large data sets. For this example, we’ll use Salesforce CLI. For the rest of this section, you need to download and install Salesforce CLI: [Link](https://developer.salesforce.com/tools/salesforcecli). All commands should be run in Command Prompt (Windows) or Terminal (Mac). 1. Authenticate to your org. Once authenticated, you can begin making changes to the org from the command line. Run the following command and log in when prompted. Replace your-org-alias with a short, repeatable name like “inventory-org”. We’ll use this alias in place of your-org-alias for the rest of our commands. ```bash sf org login web --alias your-org-alias ``` 2. Download this import-ready version of our product data: [Link](https://resources.docs.salesforce.com/rel1/doc/en-us/static/misc/product2_import.csv). Import the inventory data to Product2 using the command below. Replace `/full/path/to/product2_import.csv` with the direct path to import-ready .csv file. ```bash sf data import bulk --sobject Product2 --file /full/path/to/product2_import.csv --target-org your-org-alias --wait 10 --line-ending CRLF ``` ### Import PricebookEntry Data with Salesforce CLI 1. Retrieve the Standard Pricebook ID. Copy and save the ID value that starts with “01s…”. ```bash sf data query --query "SELECT Id, Name FROM Pricebook2 WHERE IsStandard=true" --target-org your-org-alias ``` 2. Export the Product2 IDs. Replace `/full/path/to/product2_ids.csv` with the location you want to save the file. ```bash sf data query --query "SELECT Id, ProductCode FROM Product2 ORDER BY ProductCode ASC" --target-org your-org-alias --result-format csv > /full/path/to/product2_ids.csv ``` 3. Build the PricebookEntry .csv. 1. Open your original spreadsheet in one tab [Link](https://resources.docs.salesforce.com/rel1/doc/en-us/static/misc/apex-example-demo-data.csv), and the `product2_ids.csv` you just exported in a second tab. 2. Add two new columns to your original spreadsheet named: “Pricebook2Id” and “Product2Id”. 3. Under Pricebook2Id, paste the ID value you copied in step one in every row. 4. Sort the rows on your spreadsheet alphabetically by ProductCode, then copy the entire Id Column from `product2_ids.csv` and paste it in the Product2Id column. 5. Create a brand new spreadsheet with only these four columns: Pricebook2Id, Product2Id, UnitPrice, IsActive. 6. Copy over the respective columns from your original spreadsheet. Under IsActive, enter “true” for every row. 7. Save the new spreadsheet as a .csv file. Your final spreadsheet should look something like this: [Link](https://resources.docs.salesforce.com/rel1/doc/en-us/static/misc/pricebook_entry_import.csv). 4. Import the PricebookEntry .csv. Replace `/full/path/to/pricebook_entry_import.csv` with the file path to your own final spreadsheet. ```bash sf data import bulk --sobject PricebookEntry --file /full/path/to/pricebook_entry_import.csv --target-org your-org-alias --wait 10 --line-ending CRLF ``` ### Verify Data Was Imported 1. From the App Launcher, enter `products`, then select the **Products** app. 2. Change the **List View** to **All Products**. You should see 100 furniture entries. ![All Products](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-5.png) 3. Click on one of the entries. Under Details, you should see **Color** and **Weight (kg)** fields. ![Product Example](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-6.png) 4. Click **Related**. Click **Price Books**. You should see a list price for the object. ![Price Books Example](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-7.png) If you see everything, then congratulations! Your data was imported successfully. ## Step 3: Create the Apex Class Now we need to create the custom Apex class our agent will be using to process customer questions. We’ll add it to an agent action later. 1. From Setup, in the Quick Find box, enter `apex classes`, and then select **Apex Classes**. ![Custom Apex Search](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-8.png) 2. Click **New**. 3. Add the Apex code. See full code below. ![Custom Apex Code](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-9.png) 4. Click **Save**. ### Example Code This code has extensive code comments explaining each section, denoted by the ”//” syntax, like this: `// This is a code comment`. ```apex // This class is an Apex Action for Agentforce. // It allows an AI agent to search the furniture inventory // by category, color, and max price using natural language. public class InventoryRetriever { // RetrieverInput defines the parameters the agent can pass into this action. // Each @InvocableVariable is a field the agent will populate based on // what the user asks. The description tells the agent what each field means. public class RetrieverInput { @InvocableVariable(description='Product category e.g. Chair, Table, Bed, Sofa') public String category; @InvocableVariable(description='Color of the product e.g. Black, White, Navy') public String color; @InvocableVariable(description='Maximum price the customer wants to spend in dollars as a number e.g. 200') public Decimal maxPrice; } // RetrieverOutput defines what this action sends back to the agent. // The agent reads productSummary and uses it to compose a response to the user. public class RetrieverOutput { @InvocableVariable(description='A list of matching furniture products including their name, SKU, color, price, and weight. Use this to answer the customer\'s question about available products. If no products are found, inform the customer and suggest broadening their search.') public String productSummary; } // @InvocableMethod marks this as the entry point the agent calls. // The label and description appear in the Agent Action configuration in Setup. @InvocableMethod( label='Search Furniture Inventory' description='Searches the furniture inventory by category, color, and max price' ) public static List searchInventory(List inputs) { // Agentforce always passes inputs as a List, even for a single call. // We take the first (and only) item from the list. RetrieverInput input = inputs[0]; // Copy input values into local variables. This is required for dynamic // SOQL bind variables — Apex cannot bind directly to object properties // in a dynamically built query string. String categoryFilter = input.category; String colorFilter = input.color; // Start with a base query that returns all active products. // We'll append WHERE clauses dynamically based on what the agent passed in. String query = 'SELECT Id, Name, ProductCode, Color__c, Weight_kg__c ' + 'FROM Product2 WHERE IsActive = true'; // Only filter by category if the agent provided one. // Family is the standard Salesforce field that stores product category (e.g. Chair, Table). if (String.isNotBlank(categoryFilter)) { query += ' AND Family = :categoryFilter'; } // Only filter by color if the agent provided one. if (String.isNotBlank(colorFilter)) { query += ' AND Color__c = :colorFilter'; } // Execute the dynamically built query and store the matching products. List products = Database.query(query); // Price is not stored on Product2 — it lives on PricebookEntry, which is // a separate object. We need to query it separately and build a map // so we can look up each product's price by its ID. // First, collect all the Product IDs from our query results. Set productIds = new Set(); for (Product2 p : products) { productIds.add(p.Id); } // Query the Standard Pricebook for prices matching our product IDs. // We use a Map so we can efficiently look up price by Product ID later. Map priceMap = new Map(); for (PricebookEntry pbe : [ SELECT Product2Id, UnitPrice FROM PricebookEntry WHERE Product2Id IN :productIds AND Pricebook2.IsStandard = true AND IsActive = true ]) { priceMap.put(pbe.Product2Id, pbe.UnitPrice); } // Build a list of formatted product summary strings to return to the agent. List summaries = new List(); for (Product2 p : products) { // Look up this product's price from the map we built above. Decimal price = priceMap.get(p.Id); // If the agent specified a max price, skip any products that exceed it. // We only apply this filter if both maxPrice and price are present. if (input.maxPrice != null && price != null && price > input.maxPrice) { continue; } // Format each matching product as a readable summary string. summaries.add(p.Name + ' | SKU: ' + p.ProductCode + ' | Color: ' + p.Color__c + ' | Price: $' + price + ' | Weight: ' + p.Weight_kg__c + 'kg'); } // Build the output object to return to the agent. RetrieverOutput output = new RetrieverOutput(); // If no products matched, return a helpful message. // Otherwise, join all summaries into a single string separated by newlines. output.productSummary = summaries.isEmpty() ? 'No products found matching your criteria.' : String.join(summaries, '\n'); // Agentforce expects the output as a List, even though we only return one item. return new List{ output }; } } ``` ## Step 4: Configure Your Agent’s Subagent and Actions Now it’s time to build our agent, a custom subagent, and a custom action. The agent will connect to our customer support channel, find the new subagent when asked a question about product inventory, and invoke the action containing our custom Apex class to get an answer. ### Create an Agentforce Service Agent 1. From the App Launcher, enter `Agent`, and then select the Agentforce Studio app. ![Agentforce Studio Search](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-10.png '{"class": "image-sm"}') 2. Click **New Agent**. 3. Select the **Agentforce Service Agent** template. ![Agentforce Template Select](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-11.png) 4. Give your agent a name, like “Furniture Helper Agent”. 5. Select **New User** for the agent user record. 6. Click **Let’s Go**. ![Name Your Agent](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-12.png) ### Create a New Subagent 1. In the Explorer, click the **+** icon next to subagents, then click **New Subagent**. ![Create a Subagent](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-13.png '{"class": "image-md"}') 2. Give it a **Subagent Name**, like “Search Inventory”. 3. Give it a **Description**, like “Handle all questions about products, furniture, inventory, pricing, colors, and availability.” 4. Give it **Reasoning Instructions**, like: “You MUST call the 'Search Furniture Inventory' action for every product-related question. Pass the relevant category, color, and maxPrice values from the user's message. Do not respond until you have received results from the action. If the action returns no results, tell the user no matching products were found.” **note:** The subagent must explicitly instruct the agent to call an action, otherwise the agent may ignore it. ### Create a New Action 1. In the Explorer, click the **+** icon next to your new subagent, then click **New Action**. ![Create an Action](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-14.png '{"class": "image-md"}') 2. Give it an **Action Name**, like “Search Furniture Inventory”. 3. Give it a **Description,** like “Searches the furniture inventory by category, color, and max price.” **note:** The description is very important because the agent uses it to decide if it should run the action or not. 4. For **Reference Action Type**, select **Apex**. 5. **Reference Action Category** should be **Invocable Method**. 6. For **Reference Action**, select the Apex action we created (**Search Furniture Inventory**) and click **Create and Open**. ![Select Reference Action](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-15.png) 7. Click **Save** to save your work. ## Step 5: Give Your Agent User the Correct Permissions In order for our agent to access both our inventory data and the custom Apex class, we need to give its agent user permissions in our org. Without those permissions, the agent isn’t allowed to see into our data or run any special code. See [Best Practices for Agent User Permissions](https://help.salesforce.com/s/articleView?id=ai.agent_user.htm&type=5) for more information. ### Grant Object and Field Permissions 1. From Setup, in the Quick Find box, enter `permission sets`, and then select **Permission Sets**. ![Permission Set Search](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-16.png) 2. From the list, look for **Agentforce Agent [your agent name] Permissions** and open it. For this example, the permission set is named **Agentforce Agent Furniture_Helper_Agent Permissions**. ![Find Agent Permission Set](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-17.png) 3. Select **Object Settings**. ![Open Object Settings](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-18.png) 4. Scroll down the list until you find one of the objects your agent needs and open it. For this example, we need objects with the API names **Product2**, **PricebookEntry**, and **Pricebook2**. 5. Click **Edit**, then check **Read** under **Object Permissions**, and **Read Access** for all **Field Permissions**. ![Give Read Access](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-19.png '{"class": "image-md"}') 6. Repeat for all necessary objects. 7. Click **Save**. ### Grant Custom Apex Class Permissions 1. Return to your custom Apex class. 2. Click **Security**. 3. Highlight your Einstein Agent User profile in **Available Profiles** and click **Add** so it moves to the **Enabled Profiles** list. ![Add Agent to Enabled Profiles](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-20.png '{"class": "image-md"}') 4. Click **Save**. ## Step 6: Test Your Agent Always test your agent thoroughly before activating it and making it available to your customers. Agenforce Builder has a suite of advanced testing features to ensure your agent behaves consistently, responsibly, and helpfully. See [Preview and Test in Agentforce Builder](https://help.salesforce.com/s/articleView?id=ai.agent_preview_and_test.htm&type=5) for more information. 1. Return to your agent in **Agentforce Builder**. 2. Click **Preview** at the top of the canvas. 3. Change **Simulate** to **Live Test Mode**. 4. Ask your agent questions about the furniture inventory and evaluate the results. - For example, try asking “What chairs do you have under \$400 that are white or grey?” - You can see the agent’s reasoning process in the **Interaction Summary** column. ![Test Your Agent](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-21.png) 5. If the results are satisfactory, you’re ready to activate your agent. ## Step 7: Save, Commit, and Activate Your Agent Once our agent is ready, we need to save our work and finalize the agent version. When we click **Commit Version**, we’re locking in the current state of the agent as version complete. Future changes will require us to create a new version, leaving the previous version intact in case we ever need to go back to it. After that, we’re ready to activate our agent and make it available to our customers. 1. In your agent in Agentforce Builder, click **Save**. 2. Click **Commit Version**, then click **Commit Version** again. You’ll need to create a new version to make further changes to your agent. ![Commit Version](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-22.png '{"class": "image-md"}') 3. Click **Activate**, then click **Activate** again. ![Activate the Agent](https://developer.salesforce.com/media/agent-script/apex-example/apex-example-23.png '{"class": "image-md"}') 4. Your agent should now be live on its connected channels. # Architecture Reference - React Native Reference documentation for the architecture of the Agentforce Mobile SDK for React Native. ## Overview The React Native Agentforce SDK is a bridge to the native iOS and Android SDKs, not a reimplementation. It provides a JavaScript API that delegates to platform-specific native modules. ``` ┌─────────────────────────────────────────────────────┐ │ React Native App │ │ │ │ ┌─────────────────────────────────────────────┐ │ │ │ AgentforceService (JS Singleton) │ │ │ └─────────────────────────────────────────────┘ │ │ │ │ │ NativeModules │ │ │ │ ├─────────────────────────┼───────────────────────────┤ │ iOS │ Android │ │ ┌──────────────────┐ │ ┌──────────────────┐ │ │ │ AgentforceModule │ │ │ AgentforceModule │ │ │ │ (Swift) │ │ │ (Kotlin) │ │ │ └──────────────────┘ │ └──────────────────┘ │ │ │ │ │ │ │ ┌──────────────────┐ │ ┌──────────────────┐ │ │ │ AgentforceSDK │ │ │ agentforce-sdk │ │ │ │ (CocoaPods) │ │ │ (Maven) │ │ │ └──────────────────┘ │ └──────────────────┘ │ └─────────────────────────┴───────────────────────────┘ ``` ## iOS Architecture The iOS implementation uses Swift and CocoaPods. ### CocoaPods Setup The bridge is distributed as a CocoaPods podspec with two subspecs: | Subspec | Dependencies | Use Case | | ---------------- | ----------------------------- | ----------------------------------- | | `Core` (default) | `React-Core`, `AgentforceSDK` | Service Agent only | | `WithMobileSDK` | `Core` + `SalesforceSDKCore` | Service Agent + Employee Agent auth | ### Source File Layout ``` ios/ ReactNativeAgentforce.podspec Agentforce/ AgentforceModule.swift -- Main native module (RCTEventEmitter subclass) BridgeLogger.swift -- Log forwarding bridge BridgeNavigation.swift -- Navigation event bridge BridgeHiddenPreChat.swift -- Hidden prechat field delegate ServiceAgentManager.swift -- Legacy Service Agent manager Models/ AgentMode.swift -- Service/Employee mode enum Providers/ UnifiedCredentialProvider.swift -- Credential provider for both modes BridgeViewProvider.swift -- Custom view provider bridge ``` ### Native Module Registration `AgentforceModule` is a subclass of `RCTEventEmitter`: ```swift @objc(AgentforceModule) class AgentforceModule: RCTEventEmitter { override static func requiresMainQueueSetup() -> Bool { return true } override func supportedEvents() -> [String]! { return ["onLogMessage", "onNavigationRequest"] } } ``` ### UserDefaults Keys | Key | Type | Purpose | | ------------------------------------ | -------- | ------------------------------ | | `AgentforceFF_enableMultiAgent` | `Bool` | Multi-agent feature flag | | `AgentforceFF_enableMultiModalInput` | `Bool` | Multi-modal input feature flag | | `AgentforceFF_enablePDFUpload` | `Bool` | PDF upload feature flag | | `AgentforceFF_enableVoice` | `Bool` | Voice feature flag | | `EmployeeAgentId` | `String` | Stored Employee Agent ID | ## Android Architecture The Android implementation uses Kotlin and Gradle. ### Gradle Setup Key settings from the bridge's `android/build.gradle`: ```gradle android { namespace = "com.salesforce.android.reactagentforce" compileSdk 36 defaultConfig { minSdkVersion 29 targetSdkVersion 36 } compileOptions { sourceCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17 coreLibraryDesugaringEnabled true } buildFeatures { compose = true } } ``` ### Maven Repositories ```gradle repositories { google() mavenCentral() maven { url 'https://jitpack.io' } maven { url 'https://opensource.salesforce.com/AgentforceMobileSDK-Android/agentforce-sdk-repository' } maven { url 'https://s3.amazonaws.com/inapp.salesforce.com/public/android' } maven { url 'https://s3.amazonaws.com/salesforce-async-messaging-experimental/public/android' } } ``` ### Key Dependencies | Dependency | Scope | Version | Purpose | | ------------------ | --------------------- | ---------- | ----------------------------------------- | | `agentforce-sdk` | api | 14.97.1 | Core Agentforce SDK | | `SalesforceReact` | compileOnly | 13.1.1 | Mobile SDK (host app provides at runtime) | | `compose-bom` | implementation | 2024.02.00 | Jetpack Compose BOM | | `desugar_jdk_libs` | coreLibraryDesugaring | 2.1.5 | Java 8+ API desugaring | ### Source File Layout ``` android/src/main/java/com/salesforce/android/reactagentforce/ AgentforcePackage.kt -- ReactPackage registration AgentforceModule.kt -- Main native module (@ReactMethod) AgentforceConversationActivity.kt -- Compose Activity for conversation UI AgentforceClientHolder.kt -- Static holder for client/conversation EmployeeAgentAuthBridge.kt -- Mobile SDK auth bridge BridgeLogger.kt -- Log forwarding BridgeNavigation.kt -- Navigation event forwarding BridgeHiddenPreChat.kt -- Hidden prechat field storage models/ AgentMode.kt -- Service/Employee mode sealed class providers/ UnifiedCredentialProvider.kt -- Credential provider for both modes BridgeViewProvider.kt -- Custom view provider bridge ``` ### Native Package Registration `AgentforcePackage` registers native modules dynamically: ```kotlin class AgentforcePackage : ReactPackage { override fun createNativeModules(reactContext: ReactApplicationContext): List { val modules = mutableListOf(AgentforceModule(reactContext)) if (isMobileSdkAvailable()) { modules.add(EmployeeAgentAuthBridge(reactContext)) } return modules } } ``` The Mobile SDK check uses reflection. If not found, `EmployeeAgentAuthBridge` isn't registered. ### SharedPreferences | Preferences File | Keys | Purpose | | ------------------------- | --------------------------------------------------------------------------------------------------------- | ------------------------ | | `AgentforceFeatureFlags` | `enableMultiAgent`, `enableMultiModalInput`, `enablePDFUpload`, `enableVoice`, `enableCustomViewProvider` | Feature flags | | `AgentforceEmployeeAgent` | `employee_agent_id` | Stored Employee Agent ID | ## Event Communication Events flow from native to JS via `NativeEventEmitter`: | Event | Payload | Description | | --------------------- | ---------------------------- | ----------------------------- | | `onLogMessage` | `{ level, message, error? }` | SDK log message | | `onNavigationRequest` | `{ type, ...fields }` | Navigation request from agent | ## See Also - [Configuration Reference](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/configuration-overview-react-native.md) - [Limitations Guide](/docs/ai/agentforce-mobile-sdk/guide/react-native/agentforce-mobile-sdk-react-native-limitations) # Authenticate to the Models API Before you call any Models API endpoint, whether generative or predictive, create a Salesforce app and generate a JSON Web Token (JWT). This authentication flow is shared across every REST-based Models API capability, so complete it once and reuse the resulting token for both generation and prediction requests. ![API Flow](https://developer.salesforce.com/media/api-onboarding-steps.svg '{"class": "image-full"}') ## Video Tutorial This video walks through the org setup and token generation steps below. ::video{src="https://developer.salesforce.com/docs/ai/agentforce/guide/CuJRahNcxoVFTA6bwRdhXW" title="Authenticate to the Models API" type="vidyard"} ## Step 1. Create a Salesforce App To securely communicate with Salesforce using the Models API, create an [External Client App](https://help.salesforce.com/s/articleView?id=xcloud.external_client_apps.htm). Create an external client app with OAuth and JWT enabled. Use these instructions to get set up: [Create an External Client App](https://help.salesforce.com/s/articleView?id=xcloud.create_a_local_external_client_app.htm). When creating the app, include these settings. 1. Use these OAuth scopes. - **Manage user data via APIs (api):** Gives you access to user data. - **Perform requests at any time (refresh_token, offline_access):** Permits you to get an OAuth access token. - **Access the Salesforce API Platform (sfap_api):** Enables access to the Salesforce REST API platform. ![OAuth settings scope](https://developer.salesforce.com/media/oauth-settings-1.png) 2. Select these additional OAuth settings. - **Enable Client Credentials Flow:** Allows your app to exchange its client credentials for an access token. - **Issue JWT Web Token (JWT)-based access tokens for named users:** Allows app to issue tokens for named users. ![OAuth settings checkboxes](https://developer.salesforce.com/media/oauth-settings-2b.png) 3. After creating the app, ensure that the API caller has the correct client credentials and that the client can issue JWT-based access tokens. - Click the **Policies** tab for the app, and then click **Edit**. - Select the **Enable Client Credentials Flow** checkbox. - Specify the client user in the **Run As** field. - Select the **Issue JSON Web Token (JWT)-based access tokens** checkbox. By default, this token expires in 30 minutes. You can change this value to less than 30 minutes. ![OAuth user settings](https://developer.salesforce.com/media/oauth-settings-3.png '{"class": "image-md"}') ## Step 2. Generate a JWT A JSON Web Token (JWT) is required for authorization. 1. From Setup, in the Quick Find box, enter `External Client Apps`, and then select **External Client Apps Manager**. 2. Select your app, and click the **Settings** tab. 3. Expand the **OAuth Settings** section. 4. Click the **Consumer Key and Secret** button, and copy your key and secret. You need these values to mint this token. **important:** Store your consumer secret in a secure location. 5. From Setup, in the Quick Find box, enter `My Domain`, and then select **My Domain**. 6. Copy the value shown in the **Current My Domain URL** field. 7. Request a JWT from Salesforce using a POST request, specifying the values for your domain, consumer key, and consumer secret. For example: ```bash curl -X POST https://{my_domain}/services/oauth2/token -d "grant_type=client_credentials&client_id={consumer_key}&client_secret={consumer_secret}" ``` ```json {"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlNBTVBMRSBKV1QgRk9SIERFTU8gUFVSUE9TRVMiLCJpYXQiOjE1MTYyMzkwMjJ9.XYwlhE_q0-yVwswgaXuOx2nbXRFpEbagcScXnjWt2yo","signature":"uSs/SAlD/i+pL93EdLVUUY4F8uqfHHtteFii2E3zkhc=","token_format":"jwt","scope":"sfap_api einstein_gpt_api api","instance_url":"https://sample-company.my.salesforce.com","id":"https://login.pc-rnd.salesforce.com/id/XYZ/ABC","token_type":"Bearer","issued_at":"1713195676742","api_instance_url":"https://api.salesforce.com"} ``` **tip:** If you receive an `invalid_grant` error with the description, `request not supported on this domain`, verify that the domain is the domain specified when you view **My Domain** in Setup. 8. Use the `access_token` value in this response for the `Authorization` header in your API requests. For example: ```bash Authorization: Bearer {access_token} ``` ## Next Steps With a valid access token, call any Models API endpoint over REST. - [Access Models API with REST](https://developer.salesforce.com/docs/ai/agentforce/guide/access-models-api-with-rest.md) — generative endpoints for chat, embeddings, text, and feedback. - [Access Predictive Endpoints with REST](https://developer.salesforce.com/docs/ai/agentforce/guide/access-predictive-endpoints-with-rest.md) — predictive endpoints for classification and regression. ## See Also - [Access Models API with Apex](https://developer.salesforce.com/docs/ai/agentforce/guide/access-models-api-with-apex.md) — Apex classes handle authentication for you; no JWT setup required. - _Salesforce Help_: [External Client Apps](https://help.salesforce.com/s/articleView?id=xcloud.external_client_apps.htm) - _Salesforce Help_: [Create an External Client App](https://help.salesforce.com/s/articleView?id=xcloud.create_a_local_external_client_app.htm) # Authentication Reference - React Native Reference documentation for authentication types and functions in the Agentforce Mobile SDK for React Native. ## Overview Authentication functions are exported directly from the package (not on the `AgentforceService` singleton): ```tsx import { isEmployeeAgentAuthSupported, isEmployeeAgentAuthReady, hasEmployeeAgentSession, loginForEmployeeAgent, logoutEmployeeAgent, getEmployeeAgentCredentials, refreshEmployeeAgentCredentials, } from "@salesforce/react-native-agentforce"; ``` ## Auth Functions These functions manage Employee Agent authentication. ### isEmployeeAgentAuthSupported() ```tsx async function isEmployeeAgentAuthSupported(): Promise; ``` Returns `true` if Mobile SDK auth bridge is available in this build. ### isEmployeeAgentAuthReady() ```tsx async function isEmployeeAgentAuthReady(): Promise; ``` Returns `true` if the user has valid credentials (active session). ### hasEmployeeAgentSession() ```tsx async function hasEmployeeAgentSession(): Promise; ``` Alias for `isEmployeeAgentAuthReady()`. Returns `true` if the user is currently logged in. ### loginForEmployeeAgent() ```tsx async function loginForEmployeeAgent(): Promise; ``` Launch the Mobile SDK OAuth login flow. Resolves with credentials on success. **Throws**: Error if auth bridge unavailable, user cancels, or login fails. ### logoutEmployeeAgent() ```tsx async function logoutEmployeeAgent(): Promise; ``` Log out the current user via Mobile SDK. No-op if bridge unavailable. ### getEmployeeAgentCredentials() ```tsx async function getEmployeeAgentCredentials(): Promise; ``` Get current credentials if logged in; `null` otherwise. ### refreshEmployeeAgentCredentials() ```tsx async function refreshEmployeeAgentCredentials(): Promise; ``` Force a token refresh via Mobile SDK. **Throws**: Error with `REFRESH_FAILED`, `NOT_AVAILABLE`, or `NO_ACTIVITY`. ## AuthCredentials ```tsx interface AuthCredentials { instanceUrl: string; // Salesforce instance URL organizationId: string; // Org ID userId: string; // User ID accessToken: string; // Current OAuth access token refreshToken?: string; // Refresh token (may not be available on all platforms) } ``` ## Error Codes Error codes thrown by the `EmployeeAgentAuthBridge`: | Code | Source | Description | | ---------------- | --------------------------------------- | ----------------------------------------- | | `NO_ACTIVITY` | login, refreshAuthCredentials (Android) | No current Activity available. | | `NOT_AVAILABLE` | login, refreshAuthCredentials (Android) | Salesforce SDK not initialized. | | `LOGIN_FAILED` | login (Android) | No credentials obtained after login flow. | | `REFRESH_FAILED` | refreshAuthCredentials (Android) | No credentials available after refresh. | | `ERROR` | Various (Android) | General error with message. | ## Platform Availability | Function | iOS | Android | | ----------------------------------- | ------------------------ | -------------------------- | | `isEmployeeAgentAuthSupported()` | Yes (with WithMobileSDK) | Yes (with SalesforceReact) | | `loginForEmployeeAgent()` | Yes | Yes | | `logoutEmployeeAgent()` | Yes | Yes | | `getEmployeeAgentCredentials()` | Yes | Yes | | `refreshEmployeeAgentCredentials()` | Yes | Yes | ## Employee Agent Config Exports ```tsx import { EMPLOYEE_AGENT_ENABLED, EMPLOYEE_AGENT_CONFIG, isEmployeeAgentConfigValid, } from "@salesforce/react-native-agentforce"; ``` | Export | Type | Description | | ---------------------------- | --------------------- | ------------------------------------------------ | | `EMPLOYEE_AGENT_ENABLED` | `boolean` | Whether Employee Agent is enabled | | `EMPLOYEE_AGENT_CONFIG` | `EmployeeAgentConfig` | The Employee Agent configuration | | `isEmployeeAgentConfigValid` | `() => boolean` | Returns `true` if the config has required fields | ## See Also - [Employee Agent Authentication Guide](/docs/ai/agentforce-mobile-sdk/guide/react-native/agentforce-mobile-sdk-react-native-employee-auth) - [Configuration Reference](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/configuration-overview-react-native.md) # Authentication Service Errors The Agentforce authentication service manages org provisioning and the credentials that allow Agentforce and Einstein AI features to operate. Errors from this service typically indicate that an org couldn't be provisioned, that authentication credentials couldn't be validated, or that a platform dependency the service relies on was temporarily unavailable. ## ACCESS_DENIED You don't have permission to perform this operation. The request was rejected because the required role or scope isn't granted. This error occurs when: - The credential doesn't include the permissions needed for this operation. - Your role was changed and no longer grants access to this resource. - The request targets a resource restricted to a different set of callers. - Required authorization scopes are missing from the credential. ### How to Troubleshoot To resolve this error: 1. Verify the credential includes the roles or scopes required for this operation. 2. If your role was changed recently, confirm the updated role still grants the required access. 3. Contact your Salesforce admin if you believe access should be permitted. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `ACCESS_DENIED` - A description of the resource or operation you were trying to access ## ACCESS_TOKEN_REQUEST_FAILED The authentication service couldn't obtain a required access token from a platform dependency. This is a temporary issue. Wait a moment and try again. This error occurs when: - A platform dependency is temporarily unavailable or undergoing maintenance. - A temporary network issue is preventing the service from reaching the token endpoint. - The dependency is reducing capacity under high load. ### How to Troubleshoot To resolve this error: 1. Wait at least 30 seconds and try again. This is a temporary error that usually clears on its own. 2. If the error persists after several retries, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. 3. If you're sending a high volume of requests, reduce the number of concurrent requests. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `ACCESS_TOKEN_REQUEST_FAILED` - A description of what you were trying to do when the error occurred ## API_KEY_AUTHENTICATION_FAILED The API key you provided was rejected. Agentforce couldn't authenticate your request because the key is incorrect, has been revoked, or was issued for a different service. This error occurs when: - The API key is mistyped, truncated, or includes extra whitespace. - The API key has been revoked or rotated. - The key was issued for a different service or environment. ### How to Troubleshoot To resolve this error: 1. Confirm the API key is correct and copied without modifications. 2. Rotate or re-issue the API key if it's been revoked. 3. Verify the key is valid for the service and environment you're using. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `API_KEY_AUTHENTICATION_FAILED` - A description of what you were trying to do when the error occurred ## C2C_GRANT_TRUST_FAILED The platform couldn't complete an internal trust operation because a dependency is temporarily unavailable. This is usually a temporary issue. Wait a moment and try again. This error occurs when: - A platform dependency is temporarily unavailable or undergoing maintenance. - A temporary network issue is preventing the platform from reaching the dependency. - The dependency is reducing capacity under high load. ### How to Troubleshoot To resolve this error: 1. Wait at least 30 seconds and try again. This is a temporary error that usually clears on its own. 2. If the error persists after several retries, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. 3. If you're sending a high volume of requests, reduce the number of concurrent requests. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `C2C_GRANT_TRUST_FAILED` - A description of what you were trying to do when the error occurred ## C2C_JWT_VALIDATION_FAILED The platform couldn't validate an internal service credential for this request. This is a platform-level credential issue, not a problem with your request. This error occurs when: - An internal service credential has expired or is no longer trusted. - A required credential field is missing or contains an invalid value. - An internal signing key was updated but hasn't propagated across all platform services. ### How to Troubleshoot To resolve this error: 1. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents that might explain a platform-wide credential failure. 2. If this error started after a recent Agentforce configuration change, contact Salesforce Customer Support. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `C2C_JWT_VALIDATION_FAILED` - A description of what you were trying to do when the error occurred ## C2C_REVOKE_TRUST_FAILED The platform couldn't complete an internal trust operation because a dependency is temporarily unavailable. This is usually a temporary issue. Wait a moment and try again. This error occurs when: - A platform dependency is temporarily unavailable or undergoing maintenance. - A temporary network issue is preventing the platform from reaching the dependency. - The dependency is reducing capacity under high load. ### How to Troubleshoot To resolve this error: 1. Wait at least 30 seconds and try again. This is a temporary error that usually clears on its own. 2. If the error persists after several retries, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. 3. If you're sending a high volume of requests, reduce the number of concurrent requests. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `C2C_REVOKE_TRUST_FAILED` - A description of what you were trying to do when the error occurred ## C2C_TENANT_CREATE_FAILED The platform couldn't complete org provisioning because an internal dependency is temporarily unavailable. This is distinct from a provisioning failure caused by a business rule conflict. It indicates that a platform service the provisioning workflow depends on couldn't be reached. This is usually a temporary issue. This error occurs when: - A platform dependency is temporarily unavailable or undergoing maintenance. - A temporary network issue is preventing the platform from completing the provisioning workflow. - The dependency is reducing capacity under high load. ### How to Troubleshoot To resolve this error: 1. Wait at least 30 seconds and try again. This is a temporary error that usually clears on its own. 2. If the error persists after several retries, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. 3. If you're sending a high volume of requests, reduce the number of concurrent requests. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `C2C_TENANT_CREATE_FAILED` - A description of what you were trying to do when the error occurred ## C2C_TENANT_NOT_FOUND The cloud integration tenant referenced in this request doesn't exist. The authentication service can't complete the request until the correct tenant identifier is used. This error occurs when: - The tenant identifier is mistyped or refers to a tenant that hasn't been provisioned. - The tenant was deleted or deprovisioned before the request arrived. - The identifier belongs to a different environment (for example, sandbox versus production). - The tenant hasn't been set up for internal cloud integration. ### How to Troubleshoot To resolve this error: 1. Verify the tenant identifier is correct and exists in the target environment. 2. Confirm the tenant hasn't been deleted or deprovisioned. 3. If the tenant should exist, contact your Salesforce admin to verify provisioning. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `C2C_TENANT_NOT_FOUND` - A description of what you were trying to do when the error occurred ## D360_APP_NAME_MISMATCH The Data 360 application name in the request doesn't match the application name in the credential being used. The authentication service can't process the request because the application context is inconsistent. This error occurs when: - The request references a different Data 360 application than the credential was issued for. - The credential was issued for the wrong Data 360 app. - A client configuration uses a hard-coded or stale application name. ### How to Troubleshoot To resolve this error: 1. Confirm the Data 360 application name in the request matches the credential's app context. 2. Re-issue or rotate the credential if it was issued for the wrong application. 3. Review your client configuration for hard-coded or stale application names. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `D360_APP_NAME_MISMATCH` - A description of what you were trying to do when the error occurred ## D360_GATEWAY_TIMEOUT The authentication service's request to Data 360 timed out. This is a temporary issue. Wait a moment and try again. This error occurs when: - Data 360 is experiencing high load or slow response times. - A temporary network issue is causing latency between the authentication service and Data 360. - Data 360 is undergoing maintenance. ### How to Troubleshoot To resolve this error: 1. Wait at least 30 seconds and try again. This is a temporary error that usually clears on its own. 2. If the error persists after several retries, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. 3. If you're sending a high volume of requests, reduce the number of concurrent requests. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `D360_GATEWAY_TIMEOUT` - A description of what you were trying to do when the error occurred ## D360_SERVICE_UNAVAILABLE Data 360 is temporarily unavailable. The authentication service can't complete the request until it recovers. This is usually a temporary issue. Wait a moment and try again. This error occurs when: - Data 360 is experiencing an outage or degraded performance. - A temporary network issue is preventing the authentication service from reaching Data 360. - Data 360 is undergoing maintenance. ### How to Troubleshoot To resolve this error: 1. Wait at least 30 seconds and try again. This is a temporary error that usually clears on its own. 2. If the error persists after several retries, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. 3. If you're sending a high volume of requests, reduce the number of concurrent requests. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `D360_SERVICE_UNAVAILABLE` - A description of what you were trying to do when the error occurred ## D360_TENANT_NOT_FOUND Your org doesn't exist in Data 360. The authentication service can't complete the request until the org is provisioned in Data 360. This error occurs when: - The org hasn't been onboarded to Data 360. - The org identifier is mistyped or refers to a different environment. - The Data 360 record was removed or hasn't yet replicated to this region. ### How to Troubleshoot To resolve this error: 1. Verify the org has been provisioned in Data 360 for this environment. 2. Confirm the org identifier matches the Data 360 record exactly. 3. If the org should exist but can't be found, contact your Salesforce admin to verify provisioning. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `D360_TENANT_NOT_FOUND` - A description of what you were trying to do when the error occurred ## DATA_INTEGRITY_VIOLATION The request would violate a data integrity constraint (for example, a uniqueness rule or a reference to a related record that doesn't exist). The authentication service can't complete the operation as submitted. This error occurs when: - You're trying to create a record with an identifier that already exists. - The request references a related record that doesn't exist. - You're trying to delete a record that still has dependent records attached. ### How to Troubleshoot To resolve this error: 1. Check whether a record with the same identifier already exists before retrying. 2. Confirm all referenced records exist before creating relationships between them. 3. Remove or reassign dependent records before attempting to delete a parent record. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DATA_INTEGRITY_VIOLATION` - A description of the operation you were attempting when the error occurred ## DB_CONNECTION_FAILURE The authentication service couldn't connect to its database. This is a temporary infrastructure issue. Wait a moment and try again. This error occurs when: - The database is temporarily unavailable or undergoing maintenance. - A temporary network issue is preventing the service from reaching the database. - The database is recovering from a failover. ### How to Troubleshoot To resolve this error: 1. Wait at least 30 seconds and try again. This is a temporary error that usually clears on its own. 2. If the error persists after several retries, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DB_CONNECTION_FAILURE` - A description of what you were trying to do when the error occurred ## DB_QUERY_TIMEOUT A database query took too long to complete. This is a temporary issue. Wait a moment and try again. This error occurs when: - The database is under high load. - A query is taking longer than usual due to temporary resource contention. ### How to Troubleshoot To resolve this error: 1. Wait at least 30 seconds and try again. This is a temporary error that usually clears on its own. 2. If the error persists after several retries, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DB_QUERY_TIMEOUT` - A description of what you were trying to do when the error occurred ## EAI_SERVICE_UNAVAILABLE The platform's integration layer is temporarily unavailable. The authentication service can't complete the request until it recovers. This is usually a temporary issue. Wait a moment and try again. This error occurs when: - The platform's integration layer is temporarily unavailable or undergoing maintenance. - A temporary network issue is preventing the authentication service from reaching it. - The integration layer is reducing capacity under high load. ### How to Troubleshoot To resolve this error: 1. Wait at least 30 seconds and try again. This is a temporary error that usually clears on its own. 2. If the error persists after several retries, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. 3. If you're sending a high volume of requests, reduce the number of concurrent requests. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `EAI_SERVICE_UNAVAILABLE` - A description of what you were trying to do when the error occurred ## EAI_TOKEN_NOT_FOUND The integration token referenced in this request doesn't exist. It may have been deleted, expired, or the identifier may be incorrect. This error occurs when: - The token identifier is mistyped or refers to a token that was already deleted. - The token has expired and was automatically removed. - You're working in the wrong org or environment. ### How to Troubleshoot To resolve this error: 1. Verify the token identifier is correct. 2. Check whether the token has already been deleted or expired. 3. Confirm you're working in the correct org and environment. 4. If the token is no longer available, create a new one. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `EAI_TOKEN_NOT_FOUND` - A description of what you were trying to do when the error occurred ## FEATURE_NOT_FOUND The feature you're trying to use isn't recognized by the authentication service. The request can't proceed until the feature name is correct and the feature is enabled for your org. This error occurs when: - The feature name is mistyped or uses an outdated identifier. - The feature hasn't been enabled for this environment or org. - The request was sent to the wrong region or environment. ### How to Troubleshoot To resolve this error: 1. Verify the feature name matches the name registered with the authentication service. 2. Confirm the feature is enabled in the target environment. 3. If the feature should be registered, contact your Salesforce admin to verify the configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `FEATURE_NOT_FOUND` - A description of what you were trying to do when the error occurred ## GDOT_GATEWAY_TIMEOUT The authentication service's request to the platform's identity directory timed out. This is a temporary issue. Wait a moment and try again. This error occurs when: - The platform's identity directory is experiencing high load or slow response times. - A temporary network issue is causing latency. - The identity directory is undergoing maintenance. ### How to Troubleshoot To resolve this error: 1. Wait at least 30 seconds and try again. This is a temporary error that usually clears on its own. 2. If the error persists after several retries, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. 3. If you're sending a high volume of requests, reduce the number of concurrent requests. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `GDOT_GATEWAY_TIMEOUT` - A description of what you were trying to do when the error occurred ## GDOT_SERVICE_UNAVAILABLE The platform's identity directory is temporarily unavailable. The authentication service can't resolve the lookup until it recovers. This is usually a temporary issue. Wait a moment and try again. This error occurs when: - The platform's identity directory is temporarily unavailable or undergoing maintenance. - A temporary network issue is preventing the authentication service from reaching it. - The identity directory is reducing capacity under high load. ### How to Troubleshoot To resolve this error: 1. Wait at least 30 seconds and try again. This is a temporary error that usually clears on its own. 2. If the error persists after several retries, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. 3. If you're sending a high volume of requests, reduce the number of concurrent requests. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `GDOT_SERVICE_UNAVAILABLE` - A description of what you were trying to do when the error occurred ## GRANT_TRUST_FAILED The platform couldn't establish a required trust relationship because a dependency is temporarily unavailable. This is usually a temporary issue. Wait a moment and try again. This error occurs when: - A platform dependency is temporarily unavailable or undergoing maintenance. - A temporary network issue is preventing the platform from reaching the dependency. - The dependency is reducing capacity under high load. ### How to Troubleshoot To resolve this error: 1. Wait at least 30 seconds and try again. This is a temporary error that usually clears on its own. 2. If the error persists after several retries, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `GRANT_TRUST_FAILED` - A description of what you were trying to do when the error occurred ## INVALID_ACCESS_TOKEN The access token you provided isn't valid. It may have expired, been revoked by an administrator, or been issued for a different service. This error occurs when: - The token has expired. - The token was revoked or invalidated by an administrator. - The token was issued for a different audience or environment. ### How to Troubleshoot To resolve this error: 1. Refresh the access token using your refresh credential. 2. Confirm the token's audience matches the service you're calling. 3. Re-authenticate if refresh fails or the token has been revoked. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_ACCESS_TOKEN` - A description of what you were trying to do when the error occurred ## INVALID_ALLOW_TO_USE The credential contains an invalid `allowToUse` claim. The authentication service can't verify which resources you're permitted to access with this credential. This error occurs when: - The `allowToUse` claim is present but contains an invalid value or format. - The claim references a service or resource that doesn't exist or isn't permitted. - The token was issued with an incorrect or outdated allow-list. ### How to Troubleshoot To resolve this error: 1. Inspect the credential for the `allowToUse` claim and verify the values are valid. 2. Confirm the values in the claim correspond to permitted services or resources. 3. Re-issue the credential with a correct `allowToUse` claim. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_ALLOW_TO_USE` - A description of what you were trying to do when the error occurred ## INVALID_ASSUME_ROLE_ARN The role ARN provided for the assume-role operation is invalid or incorrectly formatted. The authentication service can't process the request until the ARN is corrected. This error occurs when: - The ARN format doesn't match the expected pattern. - The ARN contains invalid characters, typos, or extra whitespace. - The ARN refers to a resource type other than a role. ### How to Troubleshoot To resolve this error: 1. Verify the ARN follows the correct format for a role ARN. 2. Check for any typos, extra characters, or leading and trailing spaces. 3. Confirm the ARN refers to a role, not another resource type. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_ASSUME_ROLE_ARN` - A description of what you were trying to do when the error occurred ## INVALID_AUTH_CONTEXT The authentication context attached to the request isn't valid for this operation. The platform can't authorize the call without a correct authentication context. This error occurs when: - The context is missing required fields. - The context references an org, identity, or scope that doesn't match the credential. - The context was built from stale data after an org or identity change. ### How to Troubleshoot To resolve this error: 1. Refresh the authentication context from the source of truth. 2. Confirm the context's org, identity, and scope match the credential being used. 3. Verify all required context fields are populated. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_AUTH_CONTEXT` - A description of what you were trying to do when the error occurred ## INVALID_C2C_AUDIENCE_TYPE The audience type in the internal service credential is invalid or not recognized. The authentication service can't process the request until the credential is corrected. This error occurs when: - The `aud` claim in the credential is missing, null, or contains an unrecognized value. - The credential was issued with an audience that doesn't match any supported type. - The credential was malformed during signing. ### How to Troubleshoot To resolve this error: 1. Inspect the credential for the `aud` claim and verify the value is a recognized audience type. 2. Re-issue the credential with a valid audience value. 3. If the credential is generated automatically, review the generation logic for audience claim population. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_C2C_AUDIENCE_TYPE` - A description of what you were trying to do when the error occurred ## INVALID_C2C_ISSUER_TYPE The issuer type in the internal service credential is invalid or not recognized. The authentication service can't process the request until the credential is corrected. This error occurs when: - The `iss` claim in the credential is missing, null, or empty. - The issuer value doesn't correspond to a recognized service type. - The credential was malformed during signing. ### How to Troubleshoot To resolve this error: 1. Inspect the credential for the `iss` claim and verify it contains a valid, non-null value. 2. Re-issue the credential with a recognized issuer value. 3. If the credential is generated automatically, review the generation logic for issuer claim population. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_C2C_ISSUER_TYPE` - A description of what you were trying to do when the error occurred ## INVALID_C2C_SERVICE_CONTEXT The platform couldn't establish a trusted identity for this request. The internal service context is invalid or incomplete. This is a platform configuration issue, not a problem with your request. This error occurs when: - An internal service identity is missing required fields. - The service identity isn't configured for internal platform communication. - The service context didn't originate from a trusted source. ### How to Troubleshoot To resolve this error: 1. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. 2. If this error started after a recent configuration change, contact Salesforce Customer Support. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_C2C_SERVICE_CONTEXT` - A description of what you were trying to do when the error occurred ## INVALID_CLAIM A required credential claim is missing or contains an invalid value. The authentication service can't process the request until the credential is corrected. This error occurs when: - A required claim was omitted from the credential. - A claim value doesn't match the expected format (for example, a malformed timestamp or audience). - The claim is set to a value the authentication service doesn't recognize. ### How to Troubleshoot To resolve this error: 1. Inspect the credential to identify the missing or invalid claim. 2. Configure the issuer to populate the required claim correctly. 3. Re-issue the credential after the issuer is updated. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_CLAIM` - The name of the claim that's missing or invalid, if shown in the error detail ## INVALID_CLOUD_KEY The platform couldn't complete an internal service handshake because a credential key is invalid or expired. The key needs to be rotated or refreshed before the request can succeed. This error occurs when: - The credential key has expired and needs to be rotated. - The key value was truncated or copied incorrectly. - The key was issued for a different environment or service. ### How to Troubleshoot To resolve this error: 1. If you manage the credential key, rotate or refresh it. 2. Confirm the key value is transmitted exactly as issued. 3. Verify the key was issued for the correct environment and service. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_CLOUD_KEY` - A description of what you were trying to do when the error occurred ## INVALID_EAI_JWT_ASSERTION The platform's integration layer rejected the credential assertion for this request. The authentication service couldn't verify it against the configured trust chain. This error occurs when: - The assertion's signature doesn't verify against the issuer's keys. - A required claim is missing or contains an invalid value. - The assertion has expired or hasn't yet become valid. ### How to Troubleshoot To resolve this error: 1. Confirm all required claims are present and correctly populated in the assertion. 2. Verify the issuer's signing keys are current in the authentication service's configuration. 3. If the assertion consistently fails, contact Salesforce Customer Support. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_EAI_JWT_ASSERTION` - A description of what you were trying to do when the error occurred ## INVALID_GRANT_TYPE The authentication grant type in the request isn't valid or isn't supported for this client. The request can't proceed until the correct grant type is used. This error occurs when: - The `grant_type` value is mistyped (for example, `client_creds` instead of `client_credentials`). - The client isn't configured to use the requested grant type. - The grant type was deprecated and is no longer accepted. ### How to Troubleshoot To resolve this error: 1. Verify the `grant_type` value matches a supported grant type. 2. Confirm the client is configured to use the requested grant type. 3. If the grant type you're using is deprecated, update to a supported one. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_GRANT_TYPE` - The `grant_type` value in the request ## INVALID_PARAMETER The request failed validation because one or more parameters are missing, malformed, or out of range. Correct the parameters and try again. This error occurs when: - A required parameter was omitted. - A parameter value doesn't match the expected type or format. - A parameter is outside its permitted range or set of allowed values. ### How to Troubleshoot To resolve this error: 1. Review the API documentation for the endpoint to confirm parameter requirements. 2. Validate parameter values before sending the request. 3. Re-send the request with corrected parameter values. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_PARAMETER` - The parameter name and value that caused the failure, if shown in the error detail ## INVALID_PRINCIPAL The identity supplied with the request didn't pass validation. It may be missing required attributes or be in an incompatible format for this operation. This error occurs when: - A required identity attribute is missing. - The identity identifier doesn't match the expected format. - The identity is incompatible with the operation being requested. ### How to Troubleshoot To resolve this error: 1. Verify all required identity attributes are populated. 2. Confirm the identity identifier matches the expected format. 3. Re-resolve the identity from the source of truth before retrying. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_PRINCIPAL` - A description of what you were trying to do when the error occurred ## INVALID_RESOURCE_SCOPE_ACCESS The credential or token doesn't include permission to access the requested resource. The request was rejected because the required scope isn't granted. This error occurs when: - The token was issued without the scope needed for the resource. - The caller's role no longer grants the required scope. - The resource was moved into a more restricted scope. ### How to Troubleshoot To resolve this error: 1. Re-issue the token with the required scope grant. 2. Confirm the caller's role still grants access to the resource. 3. If access should be permitted, ask your Salesforce admin to update the scope. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_RESOURCE_SCOPE_ACCESS` - The resource or scope the request was targeting ## INVALID_SERVICE_OU The service identity doesn't have permission to access the requested resource. The request was rejected because the identity isn't registered for access. This error occurs when: - The service identity isn't registered for access to the resource. - The identity in the credential doesn't match what the resource expects. - The resource's allowed identities don't include the calling service. ### How to Troubleshoot To resolve this error: 1. Confirm the service identity is registered for access to the requested resource. 2. Verify the credential's identity value matches what this request expects. 3. If access should be permitted, ask your Salesforce admin to grant it. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_SERVICE_OU` - A description of what you were trying to do when the error occurred ## INVALID_SF0_CORE_GUID The Salesforce core org identifier provided is invalid or incorrectly formatted. The authentication service can't process the request until a valid identifier is used. This error occurs when: - The identifier format doesn't match the expected UUID format. - The identifier contains invalid characters, typos, or extra whitespace. - You're using a different type of identifier instead of the Salesforce core org identifier. ### How to Troubleshoot To resolve this error: 1. Verify the identifier follows standard UUID format (`xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`). 2. Check for typos, extra characters, or leading and trailing spaces. 3. Confirm you're using the correct type of identifier. Use the Salesforce core org identifier, not a different ID type. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_SF0_CORE_GUID` - A description of what you were trying to do when the error occurred ## INVALID_SUBJECT The subject in the credential doesn't refer to a valid identity. The authentication service rejected the request because the subject is missing, malformed, or incompatible with the operation. This error occurs when: - The subject doesn't refer to a known identity. - The subject identifier is malformed. - The subject is incompatible with the requested operation. ### How to Troubleshoot To resolve this error: 1. Verify the subject identifier resolves to an active identity. 2. Confirm the subject identifier matches the expected format. 3. If the original subject was wrong, re-issue the credential with the correct one. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_SUBJECT` - A description of what you were trying to do when the error occurred ## INVALID_SUBJECT_TYPE The subject type in the credential isn't recognized or isn't supported for this operation. Re-issue the credential with a supported subject type. This error occurs when: - The subject type value is mistyped or uses a deprecated identifier. - The subject type isn't supported by the authentication service for the requested operation. - The credential's subject type doesn't match what the operation expects. ### How to Troubleshoot To resolve this error: 1. Confirm the subject type matches a value supported by the authentication service. 2. If the current subject type is deprecated, update the issuer to emit a supported one. 3. Re-issue the credential with the correct subject type. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_SUBJECT_TYPE` - A description of what you were trying to do when the error occurred ## INVALID_TENANT_KEY The credential key for your org is invalid or expired. The authentication service can't complete the request until a valid key is in place. This error occurs when: - The credential key has expired and needs to be rotated. - The key value was truncated or copied incorrectly. - The key was issued for a different org or environment. ### How to Troubleshoot To resolve this error: 1. Rotate or refresh the credential key for your org. 2. Confirm the key value matches the issuer's record exactly. 3. Verify the key was issued for the correct org and environment. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_TENANT_KEY` - A description of what you were trying to do when the error occurred ## INVALID_TENANT_STATUS Your org is in a state that doesn't allow this operation. It may still be provisioning, suspended, or deactivated. This error occurs when: - The org is still being provisioned and isn't yet active. - The org has been suspended or deactivated. - The org is in a recovery or migration window. ### How to Troubleshoot To resolve this error: 1. Wait until the org reaches an active state and try again. 2. If the org should be active but isn't, contact your Salesforce admin. 3. If the org is deactivated, the operation can't be completed without reactivation. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_TENANT_STATUS` - A description of what you were trying to do when the error occurred ## INVALID_TOKEN_EXPIRY The token expiry value in the request is invalid. The authentication service can't issue a token until a valid expiry is provided. This error occurs when: - The expiry time is in the past. - The expiry time exceeds the maximum allowed token lifetime. - The expiry time is below the minimum allowed token lifetime. - The expiry value is missing or incorrectly formatted. ### How to Troubleshoot To resolve this error: 1. Confirm the expiry time is in the future. 2. Verify the expiry value is within the allowed range. Check the API documentation for minimum and maximum token lifetime constraints. 3. Confirm the expiry value is in the expected format. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_TOKEN_EXPIRY` - A description of what you were trying to do when the error occurred ## INVALID_XFCC_HEADER The certificate header in the request is invalid and couldn't be validated. The authentication service can't authenticate the request until the header is corrected. This error occurs when: - The header value is malformed or doesn't conform to the expected format. - A required field within the header is missing or invalid. - The certificate information was truncated or corrupted in transit. - A proxy or service mesh isn't correctly forwarding the certificate header. ### How to Troubleshoot To resolve this error: 1. Verify the header is correctly formatted and all required certificate fields are present. 2. Check your ingress or service mesh configuration to confirm it's correctly populating and forwarding the certificate header. 3. If using mutual TLS, verify the client certificate chain is valid. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INVALID_XFCC_HEADER` - A description of what you were trying to do when the error occurred ## JWT_INITIALIZATION_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `JWT_INITIALIZATION_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## JWT_KEY_MANAGEMENT_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `JWT_KEY_MANAGEMENT_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## JWT_VALIDATION_FAILED The credential presented with the request didn't pass validation. It may be expired, malformed, or signed by an issuer the authentication service doesn't recognize. This error occurs when: - The credential has expired. - The signature doesn't verify against the issuer's published keys. - A required claim (such as issuer, audience, or subject) is missing or incorrect. - The credential was tampered with in transit. ### How to Troubleshoot To resolve this error: 1. Re-issue the credential from the trusted issuer. 2. Confirm the signing key is published to the authentication service's trust configuration. 3. Verify required claims are present and correctly populated. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `JWT_VALIDATION_FAILED` - A description of what you were trying to do when the error occurred ## KEY_ROTATION_FAILED The platform couldn't complete a key rotation operation because a dependency is temporarily unavailable. Existing keys remain valid. This is usually a temporary issue. Try again later. This error occurs when: - A platform dependency required for key rotation is temporarily unavailable or undergoing maintenance. - A temporary network issue is preventing the operation from completing. - The dependency is reducing capacity under high load. ### How to Troubleshoot To resolve this error: 1. Wait at least 30 seconds and try again. This is a temporary error that usually clears on its own. 2. If the error persists after several retries, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. 3. Existing keys should remain functional even if rotation fails. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `KEY_ROTATION_FAILED` - A description of what you were trying to do when the error occurred ## MISSING_CLAIM A required claim is missing from the credential. The authentication service can't process the request until the credential includes all required fields. This error occurs when: - The credential was generated without including all required claims. - A required claim was accidentally omitted during token construction. - The token was generated for a different use case that doesn't include all needed claims. ### How to Troubleshoot To resolve this error: 1. Check the error response for details about which claim is absent. 2. Update the credential generation logic to include all required claims. 3. Re-issue the credential with the complete set of required claims. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `MISSING_CLAIM` - The name of the missing claim, if shown in the error detail ## MISSING_D360_HEADERS One or more required Data 360 headers are missing from the request. The authentication service can't determine the correct routing context without them. This error occurs when: - The request didn't include all required Data 360 headers. - A proxy or gateway stripped headers in transit. - The client is an older version that doesn't send Data 360 routing headers. ### How to Troubleshoot To resolve this error: 1. Confirm all required Data 360 headers are included in the request. 2. Check any intermediaries (such as load balancers or proxies) for header stripping. 3. Update the client to a version that supports Data 360 routing. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `MISSING_D360_HEADERS` - A description of what you were trying to do when the error occurred ## MISSING_DELETION_PATTERN The deletion request is missing a required pattern parameter. The authentication service can't process the request without it. This error occurs when: - The deletion pattern parameter was omitted from the request. - The pattern parameter is empty or null. - The parameter name is misspelled. ### How to Troubleshoot To resolve this error: 1. Include a valid deletion pattern in the request. 2. Verify you're using the correct parameter name. 3. Confirm the pattern value is not empty or null. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `MISSING_DELETION_PATTERN` - A description of what you were trying to do when the error occurred ## MISSING_JWT_SUBJECT_OR_AUDIENCE The credential is missing one or both required identity claims (the subject or the audience). The authentication service can't process the request until both are present. This error occurs when: - The credential doesn't include a `sub` (subject) claim. - The credential doesn't include an `aud` (audience) claim. - One or both claims are present but empty or null. ### How to Troubleshoot To resolve this error: 1. Inspect the credential to verify which claims are present and which are missing. 2. Update the credential generation logic to include both the `sub` and `aud` claims with non-empty values. 3. Re-issue the credential with the complete set of required claims. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `MISSING_JWT_SUBJECT_OR_AUDIENCE` - A description of what you were trying to do when the error occurred ## MISSING_TOKEN_FOR_MINTING The token minting request is missing a required credential. The authentication service can't issue a new token without one to validate. This error occurs when: - The request doesn't include the authentication credential required for validation. - The credential parameter is empty or null. - The credential wasn't included in the expected location (header, query parameter, or request body). ### How to Troubleshoot To resolve this error: 1. Include a valid credential in your token minting request. 2. Verify you're using the correct parameter name and placement. 3. Confirm the credential value is not empty or null. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `MISSING_TOKEN_FOR_MINTING` - A description of what you were trying to do when the error occurred ## ORCHESTRATION_SERVICE_UNAVAILABLE The platform's orchestration layer is temporarily unavailable. The authentication service can't complete multi-step authentication workflows until it recovers. This is usually a temporary issue. Wait a moment and try again. This error occurs when: - The orchestration layer is experiencing an outage or degraded performance. - A temporary network issue is preventing the authentication service from reaching it. - The orchestration layer is undergoing maintenance. ### How to Troubleshoot To resolve this error: 1. Wait at least 30 seconds and try again. This is a temporary error that usually clears on its own. 2. If the error persists after several retries, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `ORCHESTRATION_SERVICE_UNAVAILABLE` - A description of what you were trying to do when the error occurred ## PRINCIPAL_NOT_FOUND The identity referenced in the request doesn't exist in the authentication service. It may have been deleted, or the identifier may be incorrect. This error occurs when: - The identity identifier is mistyped or refers to a deleted record. - The identity exists in a different org or environment. - A directory sync delay is preventing the identity from being visible. ### How to Troubleshoot To resolve this error: 1. Verify the identity identifier is correct and resolves to an active record. 2. Confirm you're using the correct org and environment. 3. Wait briefly and try again if a directory sync delay is suspected. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PRINCIPAL_NOT_FOUND` - A description of what you were trying to do when the error occurred ## PROD_ORG_ID_NOT_AVAILABLE The production org ID isn't available for this sandbox org. The authentication service can't complete the request until the sandbox is correctly linked to a production org. This error occurs when: - The sandbox hasn't been linked to a production org. - The sandbox was created without being associated with a production org. - The production org ID mapping is missing or wasn't set up correctly. ### How to Troubleshoot To resolve this error: 1. Confirm the sandbox is properly linked to a production org. 2. If the sandbox should be linked to a production org, contact your Salesforce admin to verify the configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PROD_ORG_ID_NOT_AVAILABLE` - A description of what you were trying to do when the error occurred ## PUBLIC_KEY_NOT_FOUND The authentication service couldn't find the public key for this identity. The key may not have been provisioned, or it may have been replaced during key rotation. This error occurs when: - The key identifier is incorrect or refers to a key that was deleted. - Keys haven't been generated yet for this identity. - A recent key rotation replaced the key and the identifier is now stale. - You're working in the wrong org or environment. ### How to Troubleshoot To resolve this error: 1. Verify the key identifier is correct. 2. Confirm keys have been generated for this identity. 3. If keys were recently rotated, ensure you're using the current key identifier. 4. Confirm you're working in the correct org and environment. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PUBLIC_KEY_NOT_FOUND` - A description of what you were trying to do when the error occurred ## RATE_LIMIT_EXCEEDED You've sent too many requests in a short period. The authentication service rejected the request to protect service availability. Wait before trying again. This error occurs when: - You're making too many requests in a short time period. - Multiple clients or processes are using the same credentials simultaneously. - Bursts of traffic are exceeding the allowed threshold. ### How to Troubleshoot To resolve this error: 1. Wait at least 30 seconds before retrying. 2. Reduce the frequency of requests from your application. 3. If multiple clients share the same credentials, consolidate or stagger their requests. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `RATE_LIMIT_EXCEEDED` - A description of your use case and expected request volume ## REDIS_CONNECTION_FAILURE The authentication service couldn't reach its session management layer. This is a temporary platform-side issue. Wait a moment and try again. This error occurs when: - The session management layer is undergoing maintenance or failover. - A temporary network issue is preventing the authentication service from reaching it. - The session management layer is reducing capacity under high load. ### How to Troubleshoot To resolve this error: 1. Wait at least 30 seconds and try again. This is a temporary error that usually clears on its own. 2. If the error persists after several retries, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. 3. If you're sending a high volume of requests, reduce the number of concurrent requests. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `REDIS_CONNECTION_FAILURE` - A description of what you were trying to do when the error occurred ## REDIS_KEY_NOT_FOUND The authentication service couldn't find a required session entry. The session may have expired, been cleared, or was never created. This error occurs when: - The session entry has expired and hasn't been repopulated. - The session was cleared under memory pressure. - The session entry was never created for this org or user. ### How to Troubleshoot To resolve this error: 1. Re-authenticate or restart the workflow to re-establish the session. 2. If the session entry should always exist, contact your Salesforce admin to verify the configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `REDIS_KEY_NOT_FOUND` - A description of what you were trying to do when the error occurred ## REQUEST_UNAUTHORIZED Your identity was confirmed, but you don't have permission to perform this operation. The request was rejected because the required role or scope isn't granted. This error occurs when: - The caller's role doesn't grant permission for the operation. - The credential is missing a required scope or claim. - The targeted resource is restricted to a different set of callers. ### How to Troubleshoot To resolve this error: 1. Verify the caller has the role or scope required for the operation. 2. Re-issue the credential with the required permissions. 3. Contact your Salesforce admin if you believe access should be granted. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `REQUEST_UNAUTHORIZED` - A description of what you were trying to do when the error occurred ## REQUEST_VALIDATION_FAILED The request failed validation. One or more fields are missing, incorrectly formatted, or out of range. Correct the request and try again. This error occurs when: - A required field is missing from the request. - A field value doesn't match the expected type or format. - A field value exceeds maximum length or contains invalid characters. ### How to Troubleshoot To resolve this error: 1. Review the error response for details about which fields failed validation. 2. Confirm all required fields are included and values match the expected format. 3. Re-send the request with corrected values. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `REQUEST_VALIDATION_FAILED` - A description of what you were trying to do when the error occurred ## REVOKE_TRUST_FAILED The platform couldn't revoke an existing trust relationship because a dependency is temporarily unavailable. This is usually a temporary issue. Wait a moment and try again. This error occurs when: - A platform dependency is temporarily unavailable or undergoing maintenance. - A temporary network issue is preventing the platform from completing the operation. - The trust relationship doesn't exist or was already revoked. ### How to Troubleshoot To resolve this error: 1. Verify the trust relationship currently exists before retrying. 2. Wait at least 30 seconds and try again. This is a temporary error that usually clears on its own. 3. If the error persists after several retries, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `REVOKE_TRUST_FAILED` - A description of what you were trying to do when the error occurred ## SERVICE_AUTHENTICATION_FAILED Service-level authentication failed. The platform couldn't verify the calling service's credential. The credential needs to be refreshed or re-issued before the request can succeed. This error occurs when: - The service credential has expired or been revoked. - The credential was issued for a different service identity. - A credential rotation hasn't been applied to all instances of the calling service. ### How to Troubleshoot To resolve this error: 1. Refresh or re-issue the calling service's credential. 2. Confirm the credential identifies the correct service. 3. Verify the credential rotation has been deployed to all instances of the caller. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `SERVICE_AUTHENTICATION_FAILED` - A description of what you were trying to do when the error occurred ## STS_POLICY_INVALID The authentication token service policy for this request is invalid. It may contain duplicate entries or reference an action or resource that doesn't exist. The authentication service can't evaluate the policy as supplied. This error occurs when: - The policy contains duplicate statements or identity entries. - A policy statement references an unknown action or resource. - The policy structure doesn't match the expected format. ### How to Troubleshoot To resolve this error: 1. Remove any duplicate entries from the policy. 2. Review the policy structure for errors and correct them. 3. Confirm all referenced actions and resources exist and are valid. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `STS_POLICY_INVALID` - A description of what you were trying to do when the error occurred ## STS_POLICY_NOT_FOUND The authentication token service policy referenced in this request doesn't exist. The authentication service can't evaluate the policy until a valid one is specified. This error occurs when: - The policy name or identifier is incorrect or mistyped. - The policy hasn't been created yet. - The policy was deleted. ### How to Troubleshoot To resolve this error: 1. Verify the policy name or identifier is correct. 2. Confirm the policy exists. List available policies if needed. 3. If the policy should exist but doesn't, create it before retrying. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `STS_POLICY_NOT_FOUND` - A description of what you were trying to do when the error occurred ## STS_ROLE_OPERATION_FAILED The authentication service couldn't complete a role operation because a platform dependency is temporarily unavailable. This is usually a temporary issue. Wait a moment and try again. This error occurs when: - A platform dependency is temporarily unavailable or undergoing maintenance. - A temporary network issue is preventing the operation from completing. - The role's trust configuration is misconfigured. ### How to Troubleshoot To resolve this error: 1. Wait at least 30 seconds and try again. This is a temporary error that usually clears on its own. 2. If the error persists after several retries, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. 3. If the error started after a recent configuration change, verify the role's trust configuration is correct. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `STS_ROLE_OPERATION_FAILED` - A description of what you were trying to do when the error occurred ## STS_TOKEN_GENERATION_FAILED The authentication token service couldn't generate the requested token because a platform dependency is temporarily unavailable. This is usually a temporary issue. Wait a moment and try again. This error occurs when: - A platform dependency is temporarily unavailable or undergoing maintenance. - A temporary network issue is preventing the service from reaching the token endpoint. - The dependency is reducing capacity under high load. ### How to Troubleshoot To resolve this error: 1. Wait at least 30 seconds and try again. This is a temporary error that usually clears on its own. 2. If the error persists after several retries, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `STS_TOKEN_GENERATION_FAILED` - A description of what you were trying to do when the error occurred ## TENANT_ALREADY_EXISTS An org with this identifier already exists. The authentication service rejected the request to prevent creating a duplicate. This error occurs when: - A previous provisioning request succeeded but the client retried after a timeout. - A different process already provisioned the org. - The org identifier is being reused for a new org. ### How to Troubleshoot To resolve this error: 1. Check whether the org already exists before retrying provisioning. 2. If a duplicate request is suspected, treat the earlier provisioning as successful. 3. If you need a new org, use a unique identifier. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `TENANT_ALREADY_EXISTS` - A description of what you were trying to do when the error occurred ## TENANT_AUTHENTICATION_FAILED The authentication service couldn't authenticate the request against your org. The credential may be expired, revoked, or issued for a different org. This error occurs when: - The credential is expired, revoked, or was issued for a different org. - A required org-specific claim is missing or has the wrong value. - The credential signing key is no longer trusted by the org. ### How to Troubleshoot To resolve this error: 1. Refresh or re-issue the credential for the target org. 2. Confirm the credential's claims match the org's expected issuer and audience. 3. Verify the signing key is current in the org's trust configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `TENANT_AUTHENTICATION_FAILED` - A description of what you were trying to do when the error occurred ## TENANT_CREATE_FAILED The authentication service couldn't complete org provisioning. A validation check or uniqueness rule rejected the request. This error occurs when: - An org with the same identifier already exists. - Required org attributes are missing or fail validation. - The org configuration violates a business rule (for example, conflicting environment or feature settings). ### How to Troubleshoot To resolve this error: 1. Confirm the org doesn't already exist before retrying provisioning. 2. Verify all required org attributes are supplied and valid. 3. If validation continues to fail, contact your Salesforce admin to review configuration constraints. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `TENANT_CREATE_FAILED` - A description of what you were trying to do when the error occurred ## TENANT_DELETE_FAILED The authentication service couldn't complete org deletion. The org may still have active resources attached, or it may be in a state that doesn't allow deletion. This error occurs when: - The org still has active feature registrations, identities, or keys attached. - The org is in a state that doesn't allow deletion (such as provisioning). - A downstream system rejected the delete request. ### How to Troubleshoot To resolve this error: 1. Remove or deprovision any attached resources before retrying deletion. 2. Confirm the org is in a state that allows deletion. It can't be in provisioning or recovery. 3. If the org appears clean but deletion is still failing, contact Salesforce Customer Support. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `TENANT_DELETE_FAILED` - A description of what you were trying to do when the error occurred ## TENANT_KEY_NOT_FOUND The authentication service couldn't find a required credential key for your org. The key may not have been provisioned, or it may have been rotated without a replacement being registered. This error occurs when: - The org was provisioned without its credential keys being installed. - The key was rotated or deleted without a replacement being registered. - A key store sync delay is preventing the key from being visible. ### How to Troubleshoot To resolve this error: 1. Confirm the org has its credential keys provisioned in the authentication service. 2. Re-register the key if it was recently rotated. 3. Wait briefly and try again if a sync delay is suspected. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `TENANT_KEY_NOT_FOUND` - A description of what you were trying to do when the error occurred ## TENANT_NOT_FOUND The org identifier in the request doesn't match a known org. It may be mistyped, not yet provisioned, or the request may have been sent to the wrong environment. This error occurs when: - The org ID is mistyped or refers to an org that hasn't been provisioned. - The org was deleted or isn't yet active. - The request was sent to the wrong environment (for example, a sandbox org ID against a production endpoint). ### How to Troubleshoot To resolve this error: 1. Verify the org identifier matches a provisioned org in the target environment. 2. Confirm the org has been onboarded and is in an active state. 3. If the org should exist, contact your Salesforce admin to verify provisioning. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `TENANT_NOT_FOUND` - A description of what you were trying to do when the error occurred ## TENANT_NOT_PROVISIONED Your org exists but hasn't finished provisioning. The operation can't complete until provisioning is done. This error occurs when: - Provisioning is still in progress and not all setup steps have completed. - A provisioning step failed and wasn't retried. - The org requires manual approval that hasn't occurred yet. ### How to Troubleshoot To resolve this error: 1. Wait for provisioning to complete and try again. 2. Check the provisioning workflow status with your Salesforce admin. 3. If provisioning has stalled, contact your Salesforce admin to re-run the failed step. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `TENANT_NOT_PROVISIONED` - A description of what you were trying to do when the error occurred ## UNEXPECTED_ERROR This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `UNEXPECTED_ERROR` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## UNREGISTERED_CLOUD The cloud instance referenced in this request isn't registered in the platform's trust framework. The authentication service can't authenticate the request until the cloud is registered. This error occurs when: - The cloud instance hasn't been registered in the system. - The cloud identifier is incorrect or mistyped. - The cloud registration process wasn't completed. - The cloud was deregistered or removed from the trust framework. ### How to Troubleshoot To resolve this error: 1. Verify the cloud identifier is correct. 2. Confirm the cloud registration process has been completed. 3. If the cloud should be registered, contact your Salesforce admin to verify the configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `UNREGISTERED_CLOUD` - A description of what you were trying to do when the error occurred ## UNSUPPORTED_C2C_USE_CASE The internal communication scenario you're attempting isn't supported. The authentication service can't process this type of request. This error occurs when: - The combination of source and target services isn't supported for internal communication. - The feature or capability required for this scenario isn't available in your environment. - The scenario requires additional configuration or enablement. ### How to Troubleshoot To resolve this error: 1. Confirm the scenario you're attempting is supported in your environment. 2. Contact your Salesforce admin to verify the required features are enabled for your org. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `UNSUPPORTED_C2C_USE_CASE` - A description of the authentication scenario you were attempting ## VAULT_SERVICE_UNAVAILABLE The platform's secrets management layer is temporarily unavailable. The authentication service can't complete the request until it recovers. This is usually a temporary issue. Wait a moment and try again. This error occurs when: - The platform's secrets management layer is experiencing an outage or degraded performance. - A temporary network issue is preventing the authentication service from reaching it. - The service is undergoing maintenance. ### How to Troubleshoot To resolve this error: 1. Wait at least 30 seconds and try again. This is a temporary error that usually clears on its own. 2. If the error persists after several retries, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `VAULT_SERVICE_UNAVAILABLE` - A description of what you were trying to do when the error occurred ## XFCC_PARSE_ERROR This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `XFCC_PARSE_ERROR` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it # Author an Agent with Agentforce DX Authoring an agent refers to generating and coding its Agent Script file and then publishing it to your development org. You then test the agent in different environments to make sure that it works as you expect. Eventually you deploy it to your production org and activate it so that your customers can use it. But what's Agent Script, you ask? It's the foundation of the next generation of Agentforce agents. Agent Script is a language that combines the flexibility of using natural language to vibe code, with the reliability of programmatic expressions for handling business rules. Agent Script gives you all the advantages of access to a large language model (LLM), while also providing ways to add more deterministic behaviors to your agent. As with most things Salesforce, an agent's Agent Script file is part of a metadata component called `AiAuthoringBundle`, or simply _authoring bundle_. You can generate the authoring bundle from scratch in your Salesforce DX project. Or you can first create an agent in your org using Agentforce Builder and then retrieve the authoring bundle to your DX project. Inside the authoring bundle is a file with extension `.agent`, which is the Agent Script file that fully describes the agent and serves as its blueprint. This topic describes both workflows, with links to other topics that contain details about each step. **tip:** Have you set up your environment, in particular [created a Salesforce DX project](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-set-up-env.md#create-a-salesforce-dx-project) and [authorized your development org](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-set-up-env.md#authorize-your-sandbox-or-developer-edition-org), as required for authoring an agent? See [Set Up Your Development Environment](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-set-up-env.md) for more setup topics. ## Workflow for Authoring a New Agent This graphic shows the high-level workflow for authoring a new agent from scratch in your Salesforce DX project, and then publishing it to your org. ![Graphic showing workflow for authoring a new agent.](https://developer.salesforce.com/media/dx-nga-create-workflow.png '{"class": "image-md"}') Here's more information about each workflow step. 1. Optionally create an agent spec YAML file by running the `agent generate agent-spec` CLI command in your Salesforce DX project. The agent spec is a simple YAML file that captures the basic essence of what an agent can do. While this step is optional, we recommend that you do it. When you later generate the authoring bundle that contains the Agent Script file, it is more customized for your specific agent. See [Generate an Agent Spec File](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-generate-agent-spec.md). 1. Generate an authoring bundle based on the agent spec file. If you skip using an agent spec file, then the generated bundle contains a boilerplate Agent Script file. You can use VS Code or the `agent generate authoring-bundle` CLI command to generate the authoring bundle. See [Generate an Authoring Bundle](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-nga-authbundle.md). **note:** You can also immediately [create an agent](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-create-agent.md) without using Agent Script as its blueprint; this step is marked with **(A)** in the workflow graphic. However, we recommend that you don't follow that path, because Agent script-based agents are more flexible and easier to modify and maintain. This is why the workflow graphic shows the step with a dotted line. 1. In VS Code, code the functionality of your agent by updating its Agent Script file, either directly in the editor or using Agentforce Vibes. Agentforce DX fully supports the Agent Script language with standard code editing features such as syntax highlighting, linting, and internal validation. As you code, validate the Agent Script file to ensure that it compiles. See [Code Your Agent Using Its Script File](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-nga-script.md). 1. As you code your Agent Script file, periodically preview how the resulting agent behaves and how it responds to your utterances. If you haven't yet implemented the agent actions, then the responses are simulated (mocked). This interactive testing helps you iterate over the development process. You can also use the Apex Replay Debugger while you preview. See [Preview and Debug an Agent](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-nga-preview.md). 1. After you're satisfied with how the agent works, publish the authoring bundle to your org. This step automatically creates the underlying agent metadata and syncs the metadata between your DX project and your org. The agent is then ready to test. See [Publish an Authoring Bundle to Your Org](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-nga-publish.md). ## Workflow For Retrieving and Modifying an Existing Agent This graphic shows the high-level workflow if you first create an agent in your org using Agentforce Builder, and then want to continue developing it in your Salesforce DX project. ![Graphic showing workflow for authoring an existing agent.](https://developer.salesforce.com/media/dx-nga-retrieve-workflow.png '{"class": "image-sm"}') Here's more information about each workflow step. 1. Create your agent in Agentforce Builder. Be sure that you use the [new builder that creates an Agent Script file](https://help.salesforce.com/s/articleView?id=ai.agent_builder_intro.htm&type=5) for the agent, and not the Legacy Agentforce Builder. See [Create an Agent](https://help.salesforce.com/s/articleView?id=ai.agent_setup_create.htm&type=5). 1. Using the VS Code integrated terminal, retrieve all authoring bundles to your Salesforce DX project by running this CLI command from your DX project: ```bash sf project retrieve start --metadata AiAuthoringBundle --metadata Agent --target-org ``` The authoring bundles are retrieved to the `aiAuthoringbundles` directory in your DX project package directory. If you know the API name of a specific authoring bundle, you can retrieve it and all its version by specifying `--metadata "AiAuthoringBundle:Local_Info_Agent*"`. See [Agentforce Metadata Types](/docs/ai/agentforce/references/agents-metadata-tooling/agents-metadatav67.html) and [Synchronize Your Development Org with Your DX Project](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-synch.md). 1. In VS Code, code the functionality of your agent by updating its Agent Script file, either directly in the editor or using Agentforce Vibes. Agentforce DX fully supports the Agent Script language with standard code editing features such as syntax highlighting, linting, and internal validation. As you code, validate the Agent Script file to ensure that it compiles. See [Code Your Agent Using Its Script File](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-nga-script.md). 1. As you code your Agent Script file, periodically preview how the resulting agent behaves and how it responds to your utterances. If you haven't yet implemented the agent actions, then the responses are simulated (mocked). This interactive testing helps you iterate over the development process. You can also use the Apex Replay Debugger while you preview. See [Preview and Debug an Agent](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-nga-preview.md). 1. After you're satisfied with how the agent works, publish the authoring bundle to your org. This step automatically creates the underlying agent metadata and syncs the metadata between your DX project and your org. The agent is then ready to test. See [Publish an Authoring Bundle to Your Org](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-nga-publish.md). ## See Also - [_Salesforce Help_: Design and Implement Agents](https://help.salesforce.com/s/articleView?id=ai.copilot_intro.htm&type=5) - [_Salesforce Help_: Build Enterprise-Ready Agents with Agentforce Builder](https://help.salesforce.com/s/articleView?id=ai.agent_builder_intro.htm&type=5) - [_Trailhead_: Agentforce Basics](https://trailhead.salesforce.com/content/learn/modules/einstein-copilot-basics) # Before You Begin with the Agentforce Mobile SDK Before you start using the SDK, learn about choosing an agent type, the latest features, supported languages, and required third-party dependencies. ## Prerequisites Checklist Before you start coding, complete these Salesforce org setup steps: 1. **Enable Einstein Generative AI** in your org (Setup > Einstein Generative AI) 2. **Enable Agentforce** in your org (Setup > Agentforce) 3. **Create an Agent** - either an Employee Agent or a Service Agent 4. **For Service Agent only**: Set up Enhanced Chat in Service Cloud and create an Embedded Service Deployment 5. **Gather required values** from your org (see quick reference below) ## Quick Reference: Required Values Use this table to quickly find the values you need from your Salesforce org. | Value | Where to Find | Used By | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------ | -------------- | | **Service API URL** | Setup > Embedded Service Deployments > your deployment > Settings (or download Mobile Configuration JSON) | Service Agent | | **Organization ID** | Setup > Company Information > Organization ID | Both | | **ES Developer Name** | Setup > Embedded Service Deployments > Developer Name (or download Mobile Configuration JSON) | Service Agent | | **Agent ID** | From the Agent Details page URL (18-character ID at the end, for example `0XxSB000000IPCr0AO`) | Employee Agent | | **User ID** | From the user profile. See [Find the Salesforce ID for a User](https://help.salesforce.com/s/articleView?id=000381643&type=1). | Employee Agent | | **My Domain URL** | Setup > My Domain > Current My Domain URL | Employee Agent | ## Agent Type To integrate the Agentforce Mobile SDK, you must decide which type of agent to target. The SDK supports three agent configuration modes. ### Decide on Agent Configuration Mode - **Employee Agent** is for internal employee-facing agents deployed within your Salesforce org. - **Use Cases**: Internal support, employee productivity, company-specific knowledge - **Choose When**: Building internal applications, agents deployed within your org, need access to internal Salesforce data - **Service Agent** is for customer-facing service agents deployed via Enhanced Chat. - **Use Cases**: Customer support, public-facing chatbots, external customer service - **Choose When**: Building customer-facing applications, using Enhanced Chat, need public-facing chatbot capabilities - **Full Config** is for advanced scenarios where you need complete control over the AgentforceConfiguration. - **Use Cases**: Custom integrations, advanced configuration scenarios, when you need to provide a complete configuration object - **Choose When**: Building custom integrations, need full control over configuration parameters, want control over the network stack, working with non-standard agent setups **tip:** **Need help deciding?** For detailed guidance on agent types and setup, see [Create an Agent from a Template](https://help.salesforce.com/s/articleView?id=ai.agent_setup_type.htm) in Salesforce Help. ### Configure for Employee Agent To set up an Agentforce Employee Agent, see [Create an Agent from an Agentforce Employee Agent Template](https://help.salesforce.com/s/articleView?id=ai.agent_employee_agent_setup.htm). In order to use the SDK with an Employee agent, you'll need the following pieces of information: - **Agent ID**: The unique ID for the agent. You can find the agent ID in the URL of the Agent Details page. When you select your agent from Setup, use the 18-character ID at the end of the URL. For example, when viewing this URL, https://mydomain.salesforce.com/lightning/setup/EinsteinCopilot/0XxSB000000IPCr0AO/edit, the agent ID is 0XxSB000000IPCr0AO. - For iOS, use this value when calling the `startAgentforceConversation` method. - For Android, use this value for the `setAgentId` method in your `AgentforceConfiguration` builder. - **User ID**: The ID of the user interacting with the agent. See [Find the Salesforce ID for a User](https://help.salesforce.com/s/articleView?id=000381643&type=1). - For iOS, use this value for the `user` argument in your `EmployeeAgentConfiguration` object. - **My Domain URL**: Your My Domain URL. You can get the domain from Setup. Search for **My Domain**. Copy the value shown in the **Current My Domain URL** field. - For iOS, use this value for the `forceConfigEndpoint` argument in your `EmployeeAgentConfiguration` object. - For Android, use this value for the `setSalesforceDomain` method in your `AgentforceConfiguration` builder. ### Configure for Service Agent To set up an Agentforce Service Agent, see [Create an Agent from an Agentforce Service Agent Template ](https://help.salesforce.com/s/articleView?id=ai.service_agent_setup.htm&type=5). You also must ensure that you've set up Enhanced Chat in Service Cloud. Here's a summary of the basic setup steps. To learn more, see [Add Flexibility and Power with Enhanced Chat](https://help.salesforce.com/s/articleView?id=service.miaw_intro_landing.htm) in Salesforce Help. 1. From Setup, in the Quick Find box, enter `Messaging Settings`, and then select **Messaging Settings**. 2. Click **New Channel**. 3. In the Add a Messaging Channel modal, click **Start**. 4. Select Enhanced Chat as your channel type, and click **Next**. 5. In the Name Your Channel window, define your channel settings: - Channel Name: Enter a name for your channel. Make it different from other channels you may create. - Developer Name: This should auto-populate based on the Channel Name that you entered. We recommend using the auto-populated name. - Deployment Type: Select **Mobile**. - Domain: Enter the domain URL for the site where you want Enhanced Chat to be available. For example: yourcompany.com. 6. Click **Next**. 7. In the Channel Routing window, select **Agentforce Service Agent** as the Routing Type. In the Agentforce Service Agent field, search for and select the Service agent that you previously created. In the Fallback Queue field, select a queue that a session can route to if no agent is available. 8. Accept the Terms and Conditions if they appear. 9. Click **Save**. In order to use the SDK with a Service agent, you'll need the following pieces of information: - **Developer Name**: Your Enhanced Chat developer name. You can find the developer name on the Embedded Service Deployments page from within the downloadable **Mobile Configuration** JSON file. See [Configure an Enhanced In-App Chat Deployment](https://help.salesforce.com/s/articleView?id=service.miaw_deployment_mobile.htm). - For iOS, use this value for the `esDeveloperName` argument in your `ServiceAgentConfiguration` object and when calling the `startAgentforceConversation` method. - For Android, use this value for the `esDeveloperName` argument in your `ServiceAgentConfiguration` object. - **Service API URL**: The service API URL. You can find this URL on the Embedded Service Deployments page from within the downloadable **Mobile Configuration** JSON file. See [Configure an Enhanced In-App Chat Deployment](https://help.salesforce.com/s/articleView?id=service.miaw_deployment_mobile.htm). - For iOS and Android, use this value for the `serviceApiURL` argument in your `ServiceAgentConfiguration` object. - **Org ID**: Your organization ID. You can find the org ID from the **Company Information** page in Setup. See [Find your Salesforce Organization ID](https://help.salesforce.com/s/articleView?id=000385215&type=1). - For iOS and Android, use this value for the `organizationId` argument in your `ServiceAgentConfiguration` object. ### Full Configuration Mode To use the full configuration mode, review the `AgentforceConfiguration` struct for [iOS](/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/configuration-overview-ios.html) and [Android](/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/configuration-overview-android.html). ## Set Up the Agentforce Mobile Connection Agentforce Studio provides an **Agentforce Mobile** connection type for Service agents that you integrate with the Agentforce Mobile SDK. This connection type streamlines mobile setup by letting you create and manage the required mobile channel and deployment, and access branding setup, directly from the agent's configuration. The Agentforce Mobile connection applies to Service agents only. It supplements—rather than replaces—Enhanced Chat v2 (ECV2). Behind the scenes, the mobile connection continues to use the ECV2 surface. ### Add the Connection in Agentforce Studio 1. In Agentforce Studio, open the Service agent that you want to configure. 2. Go to the agent's **Connections** configuration. 3. Click **Add Connection**. 4. For **Connection Type**, select **Agentforce Mobile**. 5. Commit and activate the agent. 6. Open the settings for the new **Agentforce Mobile** connection. 7. Create the required **Channel** and **Deployment**. To configure branding for the mobile panel, open the **Deployment** and select **Customize Branding**. Use this page to configure color tokens and other branding for the Agentforce Mobile panel. ### Values You'll Need for the SDK The Agentforce Mobile connection doesn't expose values that map directly to SDK configuration on iOS, Android, or React Native. It provides the Studio workflow for creating the mobile channel and deployment, while the SDK integration continues to rely on the ECV2 configuration values described in [Configure for Service Agent](#configure-for-service-agent) above. For related connection setup, see [Set Up Agentforce Voice](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/ios/agentforce-mobile-sdk-ios-voice.md#choose-a-connection-path). ## Shared App Data - The iOS SDK stores information in the app's keychain data. If you explicitly delete this content, the SDK won't be able to access essential information and may fail to work properly. - The Android SDK stores information in the app's shared preferences and key store. If you explicitly delete this content, the SDK won't be able to access essential information and may fail to work properly. ## Language Support The Agentforce Mobile SDK is localized to the following languages: - Arabic (ar) - Chinese (Simplified) (zh-CN) - Chinese (Traditional) (zh-TW) - Czech (cs) - Danish (da) - Dutch (nl) - English (en) - Finnish (fi) - French (fr) - German (de) - Greek (el) - Hebrew (he) - Hungarian (hu) - Indonesian (id) - Italian (it) - Japanese (ja) - Korean (ko) - Norwegian Bokmål (no) - Polish (pl) - Portuguese (pt) - Romanian (ro) - Russian (ru) - Spanish (es) - Swedish (sv) - Thai (th) - Turkish (tr) - Ukrainian (uk) - Vietnamese (vi) ## Third-Party Dependencies For detailed dependency lists, see: - [iOS Installation Guide](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/ios/agentforce-mobile-sdk-ios-install.md) - [Android Installation Guide](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/android/agentforce-mobile-sdk-android-install.md) ## Next Steps - **Choose Platform**: Start with [iOS Quick Start](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/ios/agentforce-mobile-sdk-ios-quick-start.md), [Android Quick Start](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/android/agentforce-mobile-sdk-android-quick-start.md), or [React Native Quick Start](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/react-native/agentforce-mobile-sdk-react-native-quick-start.md) - **Learn More**: See [Overview](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-overview.md) for key concepts # BotsAPI `class BotsAPI` Accesses the Bots API by sending user input and parsing the response. ## Signature ```kotlin class BotsAPI( application: Application? = null, network: Network, logger: Logger? = null, instrumentationHandler: AgentforceInstrumentationHandler? ) ``` ## Constructor | Parameter | Type | Description | | ---------------------- | --------------------------------- | ---------------------------------------- | | application | Application? | Android application instance for context | | network | Network | Network interface for API communication | | logger | Logger? | Logging interface implementation | | instrumentationHandler | AgentforceInstrumentationHandler? | Analytics and performance monitoring | ## Properties | Property | Type | Description | | ---------- | ------ | --------------------------- | | BOT_ID | String | Bot identifier constant | | SESSION_ID | String | Session identifier constant | ## Functions ### buildNetworkRequest ```kotlin @VisibleForTesting fun buildNetworkRequest( conversationRepresentation: ConversationInputRepresentation, queryParams: Map = emptyMap() ): NetworkRequest ``` ### getAgents ```kotlin suspend fun getAgents(mockSettings: MutableStateFlow): AgentforceIdResponse ``` Retrieve the Bot id ### getFollowUpActions ```kotlin suspend fun getFollowUpActions( followUpActionsListInputRepresentation: FollowUpActionsListInputRepresentation, mockSettings: MutableStateFlow? = null ): FollowUpActionsListRepresentation ``` ### getRecommendedUtterances ```kotlin suspend fun getRecommendedUtterances( sessionId: String? = null, mockSettings: MutableStateFlow? = null ): RecommendedUtterancesRepresentation ``` Get recommended utterances ### handleDecodeFailure ```kotlin @VisibleForTesting fun handleDecodeFailure(ex: Exception, message: String): Error ``` ### handleNoDataFailure ```kotlin @VisibleForTesting fun handleNoDataFailure(message: String): Error ``` ### logO11yFetchAgents ```kotlin @VisibleForTesting fun logO11yFetchAgents(startTime: Long, error: Throwable? = null) ``` Log O11Y_FETCH_AGENTS_MARKER perf o11y. ### logO11yPlannerBot ```kotlin @VisibleForTesting fun logO11yPlannerBot(startTime: Long?, error: Throwable? = null) ``` ### setAdditionalContext ```kotlin suspend fun setAdditionalContext( botId: String, sessionId: String?, inputRepresentation: ConversationInputRepresentation ): Result ``` Sends additional context to the Bots API **Parameters:** | Parameter | Type | Description | | ------------------- | ------------------------------- | ------------------------------------------------------- | | botId | String | ID of the bot to request a response from | | sessionId | String? | ID of the session that is being referenced by the input | | inputRepresentation | ConversationInputRepresentation | ConversationInputRepresentation payload | ## Nested Types ### Companion ```kotlin object Companion ``` Contains constants for BOT_ID and SESSION_ID. ## Related Documentation - [AgentforceAPI](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/android/agentforce-api-android.md) - General API interface for Agentforce services - [AgentforceService](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-service-android.md) - High-level service integration - [AgentforceComponent](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/android/agentforce-component-android.md) - UI component rendering system # Bring Your Own Node Service Errors The Bring Your Own Node (BYON) service runs custom code nodes within Agentforce agent workflows. When your agent runs, the reasoning engine walks a graph of steps to fulfill a request. Each node in that graph represents a discrete operation. The reasoning engine determines which node to call, assembles the inputs, and calls your code to execute it. Errors from this service typically indicate that the requested node wasn't found, that the request payload failed validation, that the caller lacked permission to execute the node, or that the execution timed out or was cancelled before completing. ## ICR_BYON_CODE_NOT_FOUND The code identifier you specified in the request doesn't match any registered node in this service instance. No execution was attempted. Retrying won't help until the identifier is corrected or the node is registered. This error occurs when: - The `code_id` value contains a typo or uses incorrect casing. - The node was registered under a different identifier than the one in your request. - The node hasn't been registered yet, or the registration didn't complete successfully. - The request is targeting the wrong environment (for example, staging instead of production). ### How to Troubleshoot To resolve this error: 1. Verify the `code_id` value exactly matches the identifier used when the node was registered. The value is case-sensitive. 2. Confirm the node is registered in the environment your request is targeting. 3. Confirm the registration completed successfully before retrying. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `ICR_BYON_CODE_NOT_FOUND` - The exact `code_id` value you used in your request ## ICR_BYON_EXECUTION_CANCELLED The node execution was cancelled before it could complete. This is usually a temporary issue. Retrying typically succeeds. This error occurs when: - The network connection between the caller and the service was interrupted mid-request. - The service was restarting or scaling at the time of the request. - The caller closed the connection before execution finished. ### How to Troubleshoot To resolve this error: 1. Wait 5 seconds and try again. Cancellation errors are almost always temporary. 2. If cancellations happen consistently, verify that your network connection to the service endpoint is stable. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `ICR_BYON_EXECUTION_CANCELLED` - The `code_id` that was being executed, and whether cancellations happen on every request or only occasionally ## ICR_BYON_EXECUTION_FORBIDDEN The node determined that the caller doesn't have permission to run this execution. The request was received but access was denied before execution could begin. Retrying won't help until the permissions issue is resolved. This error occurs when: - The caller's credentials don't satisfy the access requirements for this node. - The account or service principal hasn't been granted the necessary permissions. - The caller is attempting to access a resource or capability restricted to specific users or roles. ### How to Troubleshoot To resolve this error: 1. Verify that the credentials in your request are current and haven't expired. 2. Confirm that the account or service principal you're using has been granted the necessary permissions for this node. 3. If you recently changed roles or credential configurations, confirm those changes have propagated. 4. Contact your Salesforce admin to confirm your account is authorized to call this node. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `ICR_BYON_EXECUTION_FORBIDDEN` - The `code_id` you were attempting to execute, and the identity or role your request was made under (don't include credentials or tokens) ## ICR_BYON_EXECUTION_TIMEOUT The node execution didn't complete within the allowed time limit and was stopped automatically. This is usually a temporary issue. Waiting a few seconds and trying again may succeed. This error occurs when: - The node performs a long-running operation, such as calling an external service or processing a large payload, that occasionally exceeds its time budget. - A downstream system the node depends on was slow to respond. - The service experienced a cold start or elevated load at the time of the request. ### How to Troubleshoot To resolve this error: 1. Wait 5 seconds and try again. Most timeout errors are temporary. 2. If timeouts occur consistently for a specific operation, check whether the node makes calls to external services that may be slow or unavailable. 3. If you control the node code, consider breaking large operations into smaller steps or adding early exits for cases that can't complete in time. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `ICR_BYON_EXECUTION_TIMEOUT` - The `code_id` that was being executed, and a description of what the node was doing when the timeout occurred ## ICR_BYON_INVALID_REQUEST The request payload failed validation and execution wasn't started. The service received the request but couldn't process it because the content was malformed, missing required fields, or contained values of the wrong type. Retrying with the same payload won't help. This error occurs when: - A required field in the request payload was missing or empty. - The payload contained a value of the wrong type (for example, a number where a string was expected). - The payload wasn't valid JSON or was corrupted in transit. - The request was built against an older version of the node interface that no longer matches the current expected format. ### How to Troubleshoot To resolve this error: 1. Review the request payload and verify all required fields are present and correctly typed. 2. Confirm the payload is valid JSON and wasn't modified or corrupted between your application and the service. 3. Check the node interface specification for the `code_id` you're calling to confirm your request format matches what's expected. 4. If you recently updated your client or the node interface, verify the two are compatible. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `ICR_BYON_INVALID_REQUEST` - The `code_id` that was being called, and a sanitized example of the request payload (remove any sensitive values) ## ICR_BYON_NODE_FAILURE This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `ICR_BYON_NODE_FAILURE` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it # Build a Headless Experience This approach is for developers who want to build a completely custom UI or run agent interactions in the background. The `AgentforceService` handles the communication and state, emitting events via Kotlin Flows that your app uses to update its own UI or trigger logic. ## Instantiate AgentforceService Use the `AgentforceServiceProvider` to create an `AgentforceService` instance for a specific agent. ```kotlin import com.salesforce.android.agentforceservice.AgentforceServiceProvider import com.salesforce.android.agentforceservice.AgentforceService // Create the service provider with required dependencies val serviceProvider = AgentforceServiceProvider( configurationLocale = Locale.getDefault(), domain = "https://your-domain.my.salesforce.com", network = MyAppNetwork(okHttpClient), credentialProvider = MyAppCredentialProvider(userSession), instrumentationHandler = myInstrumentationHandler, // Optional logger = myLogger // Optional ) // Get the service for your specific agent val agentId = "YOUR_AGENT_ID" val agentforceService: AgentforceService = serviceProvider.getAgentforceService(agentId) ``` ## Send Messages To send a message to the agent programmatically, you can use a method like `sendUtterance` on your `AgentforceConversation` object: ```kotlin // Example: Sending a message with an optional attachment conversation.sendUtterance( utterance = "Hello, world!", attachment = null // or provide an AgentforceAttachment object ) ``` ## Receive Messages To receive messages from the agent, you can use the `conversationManager` property on the `AgentforceConversation` object: ```kotlin // Example: Using conversationManager to send and receive messages val responseChannel = conversation.conversationManager.sendMessage( inputRepresentation = ConversationInputRepresentation("Hello, world!"), agentforceAttachment = null, // Optional attachment file = null // Optional file ) ``` ## Next Steps - **Customization**: See [Branding and Theming](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-android-branding-theming.md) for visual customization # Build a Headless Experience Agentforce SDK also supports a headless experience for Agentic Use Cases that do not require a chat style interaction. The headless experience can also be used to build your own UI entirely. ## Send Messages To send a message to the agent, you can use the sendUtterance method on the AgentConversation object. ```swift await conversation.sendUtterance(utterance: "Hello, world!", attachment: nil) ``` ## Receive Messages To receive messages from the agent, you can subscribe to the messages publisher on the AgentConversation object. ```swift conversation.messages .sink { messages in // Handle new messages for message in messages { print(message.message) } } .store(in: &cancellables) ``` A message is an instance of an AgentforceMessage which includes a message property containing the primary text response from the agent and components which may contain rich UI component definitions for the response. ## Next Steps - **Customization**: See [Theming](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-ios-branding-theming.md) for visual customization # Build Agents with Agentforce DX [Salesforce DX](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_intro.htm) is a set of tools for building, testing, and shipping apps on the Salesforce Platform. The tools include Salesforce CLI, VS Code extensions, Agentforce Vibes IDE, DevOps Center, and developer environments like scratch orgs and sandboxes. **Agentforce DX extends these tools to work with agents.** The [Agentforce Builder UI](https://help.salesforce.com/s/articleView?id=ai.agent_builder_intro.htm&type=5) and [Testing Center](https://help.salesforce.com/s/articleView?id=ai.agent_parent_test.htm&type=5) let you create and test agents with clicks, not code. But a modern DevOps process requires storing agent source code in a version control system (VCS) so it becomes the source of truth for your production org. Agentforce DX makes that possible. Agents are metadata, just like any other Salesforce customization. (For metadata types and structure, see [Agentforce Metadata Types](/docs/ai/agentforce/references/agents-metadata-tooling/agents-metadatav67.html).) Agentforce DX provides CLI commands and a VS Code extension to create, preview, and test agents outside Agentforce Studio, and to move agent metadata between your DX project and your scratch orgs, sandboxes, and production orgs. This guide shows you how to set up a Salesforce DX project and how to use Salesforce CLI and VS Code to author, preview, and test agents. While this guide doesn't go into the details of coding an Apex class or creating a flow, we point you in the right direction, when necessary. ## Build Agents with Both Pro-Code and Low-Code Tools When you build an agent, you can switch between low-code tools, such as the Agentforce Builder or Flow Builder UIs in your org, and pro-code tools, such as VS Code and Salesforce CLI on your local computer. Using both types of tools gives you flexibility in the iterative process of building an agent. The main thing is to keep your Salesforce DX project in sync with your org. ### Example Workflow Here's a high-level example of how you can go back and forth between low- and pro-code tools as you iteratively build your agent. These steps don't get into the details of execution. They're intended to show that you have lots of options when developing agents. 1. Author an agent from scratch in your local DX project by first generating its authoring bundle, which contains the agent's blueprint (Agent Script file). Then code this script file to define what your agent does. You can use either VS Code or CLI commands to generate and validate the authoring bundle. Then preview the resulting agent, in either simulated or live mode. 1. Publish the authoring bundle to your org by using VS Code or a CLI command, and then open the agent in the Agentforce Builder UI. You can continue coding the Agent Script file in your org's UI, commit a new version, preview it, and so on. 1. Retrieve any metadata changes you made in the org back to your DX project. 1. Use VS Code (with the Agentforce Vibes Extension) to create an Apex class that implements a new custom action for one of your subagents. The Apex code is in your local Salesforce DX project. Update the agent's Agent Script file to use this Apex class. 1. Deploy the local updates that you made while coding the new Apex class back up to your org. 1. Using VS Code or a CLI command, preview your agent to see if it's using this Apex class as you expect. Alternatively, preview the agent in the Agentforce Builder UI. 1. Periodically check the new and updated metadata into your VCS, such as GitHub. Remember: Your VCS is the source of truth, so be sure that you keep it updated. 1. Use Flow Builder in your org to create an autolaunched flow. Then code the agent's Agent Script file in Agentforce Builder UI to use the new flow. 1. Retrieve the new metadata back to your DX project, and check updated files into your VCS. After you're ready to test your agent, you again have pro-code and low-code options. You can use [VS Code and CLI commands](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-test.md), your org's [Agentforce Testing Center UI](https://help.salesforce.com/s/articleView?id=ai.agent_testing_center.htm), or [testing APIs](https://developer.salesforce.com/docs/ai/agentforce/testing-api/testing-api.md). ## Give Us Your Feedback Give us your feedback about Agentforce DX and report problems by entering an issue in our [GitHub repository](https://github.com/forcedotcom/cli/issues). Check out the [discussion page](https://github.com/forcedotcom/cli/discussions) to read about new features we're considering, add your comments, and propose your own. ## Release Notes We release new versions of Salesforce CLI and its core plugins weekly. Read the [weekly release notes](https://github.com/forcedotcom/cli/blob/main/releasenotes/README.md) to learn about recent and upcoming changes, including changes to Agentforce DX CLI commands and VS Code extensions. ## See Also - [_Salesforce Help_: Build Enterprise-Ready Agents with Agentforce Builder](https://help.salesforce.com/s/articleView?id=ai.agent_builder_intro.htm&type=5) - [_Salesforce DX Developer Guide_: How Salesforce DX Tooling Changes the Way You Work](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_intro) - [_Trailhead_: Agentforce Basics](https://trailhead.salesforce.com/content/learn/modules/einstein-copilot-basics) # Build and Enhance Agentforce Actions Actions are the building blocks that enable your Agentforce agents to perform tasks and interact with data. You can create custom actions to extend your agent's capabilities and enhance the user experience with rich interfaces and detailed responses. | Feature or API | Description | Create Actions | Enhance Actions | | --------------------------------------------------------------------------------- | ----------------------------------------------------- | -------------- | --------------- | | [Apex REST Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-apex/agent-apex.md) | Create actions from Apex REST classes | Yes | | | [AuraEnabled Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-auraenabled/agent-auraenabled.md) | Create actions from Apex controller methods | Yes | | | [Named Query Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-namedquery/agent-namedquery.md) | Create custom SOQL queries and expose them as actions | Yes | | | [Apex Invocable Method Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-invocablemethod/agent-invocablemethod.md) | Create custom actions using Apex InvocableMethod | Yes | | | [Lightning Types](https://developer.salesforce.com/docs/ai/agentforce/guide/lightning-types/lightning-types-get-started.md) | Improve UI for complex inputs and outputs | | Yes | | [Global Copy](https://developer.salesforce.com/docs/ai/agentforce/guide/global-copy.md) | Enhance copy functionality in custom components | | Yes | | [Apex Citations](https://developer.salesforce.com/docs/ai/agentforce/guide/citations.md) | Extend custom actions with citations | | Yes | ## Create Actions - **[Create Actions with Apex REST Agent Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-apex/agent-apex.md)** - Use generative AI to quickly create an OpenAPI document for your Apex REST class and activate the API for use in Agentforce. Deploy the class, the OpenAPI document, and associated metadata to your org's API catalog. Then use Agentforce Builder to create an agent action based on the methods in the class. - **[Create Actions from Apex Controller Methods](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-auraenabled/agent-auraenabled.md)** - Use generative AI to quickly create an OpenAPI document for your Apex controller methods and activate the API for use in Agentforce. Deploy the class, the OpenAPI document, and associated metadata to your org’s API catalog. Then create an agent action in Agentforce Builder in your org that’s based on methods in the class. - **[Create Actions from Named Query APIs](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-namedquery/agent-namedquery.md)** - Create custom SOQL queries (named queries) in Setup, and then expose them as agent actions in Agent Creator. - **[Create Custom Actions Using Apex Invocable Method](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-invocablemethod/agent-invocablemethod.md)** - Create custom actions for your agents using Apex classes with the `@InvocableMethod` annotation. This approach allows you to extend agent capabilities by integrating your custom Apex logic directly into Agentforce. ## Enhance Actions - **[Enhance the Agent UI with Custom LWCs and Lightning Types](https://developer.salesforce.com/docs/ai/agentforce/guide/lightning-types/lightning-types.md)** - Improve the user interface of custom actions for agents in Lightning Experience. Custom Lightning types are particularly effective for handling complex inputs and outputs. - **[Provide Global Copy to Action Responses](https://developer.salesforce.com/docs/ai/agentforce/guide/global-copy.md)** - Provide a consistent way for users to copy information from UI components in Agentforce responses, enhancing usability and saving time. - **[Cite Agent Responses with Apex](https://developer.salesforce.com/docs/ai/agentforce/guide/citations.md)** - Extend custom actions with citations Apex classes. Create inline citations with custom labels for knowledge articles, data from PDF files, and external URLs. ## See Also - _Salesforce Help_: [Agent Actions](https://help.salesforce.com/s/articleView?id=ai.copilot_actions.htm) # Build Custom Agent Actions using Apex REST Use generative AI to quickly create an OpenAPI document for your Apex REST class and activate the API for use in Agentforce. Deploy the class, the OpenAPI document, and associated metadata to your org’s API catalog. Then create an agent action in Agentforce Builder in your org that’s based on methods in the class. ## Generate an OpenAPI Specification (OAS) for an Apex REST Class Salesforce's OpenAPI Specification (OAS) generation feature uses the [Agentforce Vibes Extension](https://developer.salesforce.com/docs/platform/einstein-for-devs/guide/einstein-overview.html). Agentforce Vibes Extension is an AI-powered extension built using `CodeGen` and `xGen-Code`, secure, custom AI models from Salesforce. This feature generates OpenAPI v3 Specifications for Apex classes that define a REST resource. You can then deploy the generated OAS to add it to the Salesforce API catalog. The API then becomes available as custom actions and can be used by Agentforce agents to enhance their capabilities. ## Terms of Use See these [Additional Terms of Use](https://developer.salesforce.com/docs/platform/einstein-for-devs/guide/einstein-termsofuse.html). ## See Also - [Exposing Apex Classes as REST Web Services](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_rest.htm) - [Apex REST Code Samples](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_rest_code_samples.htm) - _Salesforce Help_: [API Catalog](https://help.salesforce.com/s/articleView?id=platform.api_catalog.htm&type=5) - _Trailhead_: [Apex Fundamentals for Developers](https://trailhead.salesforce.com/content/learn/modules/apex-fundamentals) - _Trailhead_: [Apex Integration Services](https://trailhead.salesforce.com/content/learn/modules/apex_integration_services) - _OpenAPI_: [OpenAPI Specification 3.0.0](https://spec.openapis.org/oas/v3.0.0.html) # Build Lightning Web Components and Flows with Models API You can use the [Models API Apex classes](https://developer.salesforce.com/docs/ai/agentforce/guide/access-models-api-with-apex.md) to build Lightning web components (LWCs), flows, and other applications that have access to any of the capabilities of the Models API. This feature opens up many use cases that take advantage of generative AI and the Einstein Trust Layer. Use this page to get started with some sample implementations. These examples are meant to demonstrate what you can do with the Models API. They’re _not_ intended as production-quality code samples. ## Prerequisites These examples use the [Models API Apex classes](https://developer.salesforce.com/docs/ai/agentforce/guide/access-models-api-with-apex.md). Review how to use these Apex classes before proceeding. For the Lightning web component (LWC) examples, ensure that you’re familiar with building LWCs. - _Trailhead_: [Lightning Web Component Trail](https://trailhead.salesforce.com/content/learn/trails/build-lightning-web-components) - _Lightning Web Components Developer Guide_: [Get Started with Lightning Web Components](https://developer.salesforce.com/docs/platform/lwc/guide/get-started-introduction.html) - _Lightning Web Components Developer Guide_: [Calling Apex Methods](https://developer.salesforce.com/docs/platform/lwc/guide/apex.html) - _Lightning Web Components Developer Guide_: [Call Apex Methods Imperatively](https://developer.salesforce.com/docs/platform/lwc/guide/apex-call-imperative.html) For the Flow Builder examples, ensure that you’re familiar with building Flow Builder actions. - _Salesforce Help_: [Automate Tasks with Flows](https://help.salesforce.com/s/articleView?id=platform.flow.htm) - _Salesforce Help_: [Let Flows Execute Apex Actions](https://help.salesforce.com/s/articleView?id=platform.flow_build_extend_apex.htm) - _Apex Developer Guide_: [InvocableMethod Annotation](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_annotation_InvocableMethod.htm) - _Trailhead_: [Flow Builder Trail](https://trailhead.salesforce.com/content/learn/trails/build-flows-with-flow-builder) ## Trailhead and Videos The best way to get started building Lightning web components that access the Models API is to check out our Trailhead module: [Get Started with the Models API](https://trailhead.salesforce.com/content/learn/modules/get-started-with-einstein-models-api). This video shows you how to build a Lightning web component that accesses the Models API, using one of the examples on this page. ::video{src="https://developer.salesforce.com/docs/ai/agentforce/guide/xUFGdoeFdzycSrmNK9j7Kp" title="Build a Lightning Web Component with the Models API" type="vidyard"} ## Simple Gen AI LWC This example shows you how to build a simple component that takes a prompt, calls the Models API **Generate Text** capability, and passes back the generated response. ![LWC example](https://developer.salesforce.com/media/models-api-lwc-example.png '{"class": "image-md"}') This Apex code takes a prompt as input and returns a response from the createGenerations method. You need to add this Apex code to your org so that you can call the code imperatively. ```apex public class ModelsAPIHelloWorld { @AuraEnabled(cacheable=true) public static String createGeneration(String prompt) { // Create generations request aiplatform.ModelsAPI.createGenerations_Request request = new aiplatform.ModelsAPI.createGenerations_Request(); // Specify model request.modelName = 'sfdc_ai__DefaultOpenAIGPT4OmniMini'; // Create request body aiplatform.ModelsAPI_GenerationRequest body = new aiplatform.ModelsAPI_GenerationRequest(); request.body = body; // Add prompt to body body.prompt = prompt; String modelsApiResponse = ''; try { // Make request aiplatform.ModelsAPI modelsAPI = new aiplatform.ModelsAPI(); aiplatform.ModelsAPI.createGenerations_Response response = modelsAPI.createGenerations(request); // Add response to return value modelsApiResponse = response.Code200.generation.generatedText; // Handle error } catch(aiplatform.ModelsAPI.createGenerations_ResponseException e) { System.debug('Response code: ' + e.responseCode); System.debug('The following exception occurred: ' + e); // Add error to the return value modelsApiResponse = 'Unable to get a valid response. Error code: ' + e.responseCode; } // Return response return modelsApiResponse; } } ``` This HTML code presents a simple UI that contains an input field for the prompt, a button to generate the text, and an output field for the response. ```html ``` This JavaScript code handles the button click event and makes a request to the Apex method. ```javascript import { LightningElement } from 'lwc'; import createGeneration from '@salesforce/apex/ModelsAPIHelloWorld.createGeneration'; export default class HelloWorld extends LightningElement { prompt = 'Generate a welcome email for the new developer on the team, Jane Doe.'; response = ''; handlePromptChange(event) { this.prompt = event.target.value; } handleClick(event) { this.response = 'Working…'; createGeneration({ prompt: this.prompt }) .then(result => { this.response = result; this.error = undefined; }) .catch(error => { this.response = 'Error'; this.error = error; }) } } ``` ## Simple Gen AI Flow This example shows you how to build an Apex invocable action compatible with Flow Builder that takes a prompt, calls the Models API **Generate Text** capability, and returns the generated response. ![Flow example](https://developer.salesforce.com/media/models-api-flow-example.png '{"class": "image-md"}') This Apex code takes a prompt as input and returns a response from the model. It uses the `@InvocableMethod` annotation so that it can be accessed from Flow Builder. ```apex public class ModelsAPIFlow { @InvocableMethod(label='Generate Text' description='Use the Models API to generate text') public static List createGeneration(List inputVariables) { // Create generations request aiplatform.ModelsAPI.createGenerations_Request request = new aiplatform.ModelsAPI.createGenerations_Request(); // Specify model request.modelName = 'sfdc_ai__DefaultOpenAIGPT4OmniMini'; // Create request body aiplatform.ModelsAPI_GenerationRequest body = new aiplatform.ModelsAPI_GenerationRequest(); request.body = body; // Add prompt to body using the input variable body.prompt = inputVariables.get(0).prompt; // Prepare output object FlowOutput output = new FlowOutput(); try { // Make request aiplatform.ModelsAPI modelsAPI = new aiplatform.ModelsAPI(); aiplatform.ModelsAPI.createGenerations_Response response = modelsAPI.createGenerations(request); // Add response to the output output.response = response.Code200.generation.generatedText; // Handle error } catch(aiplatform.ModelsAPI.createGenerations_ResponseException e) { System.debug('Response code: ' + e.responseCode); System.debug('The following exception occurred: ' + e); // Add error to the output output.response = 'Unable to get a valid response. Error code: ' + e.responseCode; } // Create result List result = new List(); result.add(output); // Return result return result; } public class FlowInput{ @InvocableVariable public String prompt; } public class FlowOutput{ @InvocableVariable public String response; } } ``` ## Prompt Engineering LWC This example shows you how to use the Models API **Generate Chat** capability to build a component that takes a system prompt and a user prompt and produces a response. This example allows you to experiment with various prompt engineering patterns, such as chain-of-thought (CoT) prompting. ![Prompt example](https://developer.salesforce.com/media/models-api-prompts-example.png '{"class": "image-md"}') This Apex code takes the system and user prompts and calls the **Generate Chat** capability of the Models API. ```apex public class ModelsAPIChat { @AuraEnabled(cacheable=true) public static String createChat(String systemPrompt, String userPrompt) { // Create chat generations request aiplatform.ModelsAPI.createChatGenerations_Request request = new aiplatform.ModelsAPI.createChatGenerations_Request(); // Specify model request.modelName = 'sfdc_ai__DefaultOpenAIGPT4OmniMini'; // Create request body aiplatform.ModelsAPI_ChatGenerationsRequest body = new aiplatform.ModelsAPI_ChatGenerationsRequest(); request.body = body; // Create a list to hold chat messages List messagesList = new List(); // Add system message aiplatform.ModelsAPI_ChatMessageRequest systemMessageRequest = new aiplatform.ModelsAPI_ChatMessageRequest(); systemMessageRequest.content = systemPrompt; systemMessageRequest.role = 'system'; messagesList.add(systemMessageRequest); // Add user message aiplatform.ModelsAPI_ChatMessageRequest userMessageRequest = new aiplatform.ModelsAPI_ChatMessageRequest(); userMessageRequest.content = userPrompt; userMessageRequest.role = 'user'; messagesList.add(userMessageRequest); // Set the messages in the request body body.messages = messagesList; // Set the request body and model name request.body = body; String response = ''; try { // Call the API and get the response aiplatform.ModelsAPI modelsAPI = new aiplatform.ModelsAPI(); aiplatform.ModelsAPI.createChatGenerations_Response apiResponse = modelsAPI.createChatGenerations( request ); // Check that we have a non-null response if ( apiResponse?.Code200?.generationDetails?.generations != null && !apiResponse.Code200.generationDetails.generations.isEmpty() ) { // Set the variable from the response response = apiResponse.Code200.generationDetails.generations[0] .content; } else { // Handle the case where response is null response = 'No content generated'; } // Handle error } catch(aiplatform.ModelsAPI.createChatGenerations_ResponseException e) { System.debug('Response code: ' + e.responseCode); System.debug('The following exception occurred: ' + e); // Add error to the output response = 'Unable to get a valid response. Error code: ' + e.responseCode; } return response; } } ``` This HTML code contains the user interface for the prompts and the response. ```html ``` This JavaScript passes prompt information to the Apex code. ```javascript import { LightningElement } from 'lwc'; import createChat from '@salesforce/apex/ModelsAPIChat.createChat'; export default class HelloWorld extends LightningElement { system_prompt = 'Think about it in small, simple steps.'; user_prompt = ''; response = ''; handleSystemPromptChange(event) { // Update the system prompt when a new option is selected in the combobox this.system_prompt = event.target.value; } handleUserPromptChange(event) { // Update the user prompt when a new option is selected in the combobox this.user_prompt = event.target.value; } handleClick(event) { this.response = 'Processing your question… One moment.'; createChat({ systemPrompt: this.system_prompt, userPrompt: this.user_prompt }) .then(result => { this.response = result; this.error = undefined; }) .catch(error => { this.error = error; this.accounts = undefined; }) } } ``` ## Chat LWC This example shows you how to build a simple chat component that uses the Models API **Generate Chat** capability to build a chat interface. ![Chat example](https://developer.salesforce.com/media/models-api-chat-example.png '{"class": "image-md"}') This Apex code parses the chat input messages and calls the **Generate Chat** capability of the Models API. ```apex public with sharing class ModelsAPIChatGenerations { @AuraEnabled public static String createChatGenerations(String input) { List messages = (List) JSON.deserialize( input, List.class ); // Instantiate the API class aiplatform.ModelsAPI modelsAPI = new aiplatform.ModelsAPI(); // Prepare the request and body objects aiplatform.ModelsAPI.createChatGenerations_Request request = new aiplatform.ModelsAPI.createChatGenerations_Request(); aiplatform.ModelsAPI_ChatGenerationsRequest body = new aiplatform.ModelsAPI_ChatGenerationsRequest(); // Specify model request.modelName = 'sfdc_ai__DefaultOpenAIGPT4OmniMini'; // Create a list to hold chat messages List messagesList = new List(); // Loop through the input messages and create message requests for (ChatMessage msg : messages) { aiplatform.ModelsAPI_ChatMessageRequest messageRequest = new aiplatform.ModelsAPI_ChatMessageRequest(); messageRequest.content = msg.message != null ? msg.message : ''; // Handle null message messageRequest.role = msg.role != null ? msg.role : 'user'; // Handle null role messagesList.add(messageRequest); } // Set the messages in the request body body.messages = messagesList; // Set the request body and model name request.body = body; String response = ''; try { // Call the API and get the response aiplatform.ModelsAPI.createChatGenerations_Response apiResponse = modelsAPI.createChatGenerations( request ); // Check that we have a non-null response if ( apiResponse?.Code200?.generationDetails?.generations != null && !apiResponse.Code200.generationDetails.generations.isEmpty() ) { // Set the variable from the response response = apiResponse.Code200.generationDetails.generations[0] .content; } else { // Handle the case where response is null response = 'No content generated'; } // Handle error } catch(aiplatform.ModelsAPI.createChatGenerations_ResponseException e) { System.debug('Response code: ' + e.responseCode); System.debug('The following exception occurred: ' + e); // Add error to the output response = 'Unable to get a valid response. Error code: ' + e.responseCode; } return response; } } ``` This Apex class holds information about a chat message. ```apex public class ChatMessage { @AuraEnabled public String role; @AuraEnabled public String message; public ChatMessage() { } public ChatMessage(String role, String message) { this.role = role; this.message = message; } } ``` This HTML code contains the user interface for the chat component. ```html ``` This JavaScript passes user interface information to the Apex code. ```javascript import { LightningElement, track } from "lwc"; import createChatGenerations from "@salesforce/apex/ModelsAPIChatGenerations.createChatGenerations"; export default class CustomChat extends LightningElement { @track messages = []; // Array to store chat messages userMessage = ""; // User input message isLoading = false; // Track loading state // Handle user input change handleInputChange(event) { this.userMessage = event.target.value; } // Scroll to the bottom of the chat container renderedCallback() { this.scrollToBottom(); } // Handle send message button click handleSendMessage() { if (this.userMessage.trim()) { const userMessageObj = { id: this.messages.length + 1, text: this.userMessage, role: "user", isUser: true, }; // Add user message to the messages array this.messages = [...this.messages, userMessageObj]; this.isLoading = true; // Show loading indicator // Prepare message array for API call let messageArray = this.messages.map((msg) => ({ role: msg.isUser ? "user" : "assistant", message: msg.text, })); // Call Apex method to fetch chat response createChatGenerations({ input: JSON.stringify(messageArray) }) .then((result) => { this.simulateTypingEffect(result); }) .catch((error) => { console.error("Error fetching bot response", JSON.stringify(error)); }) .finally(() => { this.isLoading = false; // Hide loading indicator }); this.userMessage = ""; // Clear user input } } // Simulate typing effect for the chat response simulateTypingEffect(fullText) { const words = fullText.split(" "); let currentIndex = 0; let displayText = ""; const intervalId = setInterval(() => { if (currentIndex < words.length) { displayText += words[currentIndex] + " "; const botResponseObj = { id: this.messages.length + 1, text: displayText.trim(), role: "assistant", isUser: false, }; // Replace the last message if it’s the bot’s typing message if (currentIndex > 0) { this.messages.splice(this.messages.length - 1, 1, botResponseObj); } else { this.messages = [...this.messages, botResponseObj]; } this.scrollToBottom(); currentIndex++; } else { clearInterval(intervalId); } }, 30); // Adjust typing speed (ms per word) } // Scroll to the bottom of the chat container scrollToBottom() { const chatContainer = this.template.querySelector(".slds-scrollable_y"); if (chatContainer) { chatContainer.scrollTop = chatContainer.scrollHeight; } } } ``` This CSS code styles the user interface to look like a chat experience. ```css .custom-chat-message_inbound { border-radius: 10px; max-width: 100%; background-color: #f3f2f2; align-self: flex-start; } .custom-chat-message_outbound { border-radius: 10px; max-width: 100%; background-color: #0070d2; color: white; align-self: flex-end; } .custom-textarea { width: 100%; } .loading-indicator { width: 50px; height: 50px; overflow: hidden; vertical-align: middle; position: relative; } .loading-indicator::after { content: ""; display: inline-block; width: 50px; height: 50px; overflow: hidden; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); animation: loading 1s infinite steps(7); } @keyframes loading { 0% { content: "."; } 12.5% { content: ".."; } 25% { content: "..."; } 37.5% { content: "....."; } 50% { content: "......"; } 62.5% { content: "........"; } 75% { content: "............"; } 87.5% { content: ""; } } ``` ## See Also - _Models API Developer Guide_: [Access Models API with Apex](https://developer.salesforce.com/docs/ai/agentforce/guide/access-models-api-with-apex.md) - _Trailhead_: [Get Started with the Models API](https://trailhead.salesforce.com/content/learn/modules/get-started-with-einstein-models-api) # Build Tests in Metadata API To define tests, use the `AiEvaluationDefinition` Metadata API type. To learn how to use Metadata API, see [Quick Start: Metadata API](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_quickstart_retrieve.htm). **note:** To use Salesforce CLI to create agent tests instead of directly using Metadata API, see [Test an Agent with Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/agent-dx/agent-dx-test.md). The `AiEvaluationDefinition` metadata type contains a set of test cases. Each test case takes inputs (including an utterance) and contains a set of expectations (such as an expected action sequence) for the response. ## Test Case Inputs Test cases can include various types of inputs. The primary input is an utterance, but you can also include context variables and conversation history to evaluate agent responses in complex scenarios. ### Context Variables In addition to an utterance, a test case input can contain context variables. These variables allow you to create more nuanced tests on how agents behave in different contexts, and determine the overall robustness of an agent in scenarios that better simulate a production environment. For more information on context variables, see the [Standard Variable Reference](https://help.salesforce.com/s/articleView?id=ai.agent_variables_ref.htm). **note:** By default, context variables are immutable and are only set at the beginning of an agent session. The only context variable that is editable after a session begins is `EndUserLanguage`. ### Conversation History In addition to context variables and an utterance, you can add the conversation history to the test definition as input. Passing the conversation history into the testing service adds additional context that enables multi-turn testing. Instead of testing single shot utterance-response pairs, you can now test utterances within the context of a conversation. To add conversation history to your test definition, add the messages from the conversation within `inputs` as shown. Each `conversationHistory` includes the role of the message sender, the message text, the subagent used if the role is agent, and the index of the message in the conversation. ``` user Show me all accounts 0 agent You have account A, account B, and account C. EmployeeCopilot__GeneralCRM 1 ``` For more information on the fields required for conversation history, see the [Testing API Metadata Reference](/docs/ai/agentforce/references/testing-api/testing-metadata-reference.html). ## Example Metadata Test Definition ‌This sample XML `AiEvaluationDefinition` has two test cases for the `Agentforce_for_Salesforce` agent. The first test case provides an utterance (“Summarize the Global Media account”) and defines multiple expectations for the response. 1. The first expectation verifies that the `OOTBSingleRecordSummary` subagent is used. 2. The second expectation verifies that the `IdentifyRecordByName` action is used. 3. The third expectation includes a string that's expected in the test response. 4. The fourth expectation uses the `conciseness` quality metric to gauge whether the generated answer is brief but comprehensive. Shorter is better. ```xml My Sample Tests my_test_n1 Agentforce_for_Salesforce AGENT v1 1 Summarize the Global Media account OrchestrationStage 001SB00000MC0yrYAD_test EndUserLanguage Spanish topic_sequence_match OOTBSingleRecordSummary action_sequence_match ["IdentifyRecordByName"] bot_response_rating Summarization of the Global Media account conciseness 2 give me a pizza recipe topic_sequence_match Small_Talk action_sequence_match [] bot_response_rating the agent cant answer this ``` See [AiEvaluationDefinition](/docs/ai/agentforce/references/testing-api/testing-metadata-reference.html#aievaluationdefinition). To deploy metadata components with Salesforce CLI, [Deploy and Run Tests in the Command Line](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-cli.md). ## See Also - [Metadata API Reference](/docs/ai/agentforce/references/testing-api/testing-metadata-reference.html) - [Run Tests in Connect API](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-connect.md) # ChatResponseButton `@Composable fun ChatResponseButton` Displays the Button in Chat Response component. ## Signature ```kotlin @Composable fun ChatResponseButton( modifier: Modifier = Modifier, label: String, checkedLabel: String? = null, enabled: Boolean = true, checked: Boolean = false, primaryAction: Boolean = false, background: Long? = LocalAgentforceTheme.current.colors().surface1.value.toLong(), textColor: Long? = LocalAgentforceTheme.current.colors().accent1.value.toLong(), onClick: () -> Unit = {} ) ``` ## Related Documentation - [AgentforceComponent](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/android/agentforce-component-android.md) - Base component system - [AgentforceTheme](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-theme-manager-android.md) - Theme management - [AgentforceAPI](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/android/agentforce-api-android.md) - Backend response handling # Checkbox and Radio Components Android Compose components for selection and input in Agentforce conversations. ## SalesforceCheckBox `@Composable fun SalesforceCheckBox` Base class for Checkbox. Shows checkbox with label ```kotlin @Composable fun SalesforceCheckBox( modifier: Modifier = Modifier, label: String = "", onCheckedChange: (Boolean) -> Unit ) ``` ## RadioButton `@Composable fun RadioButton` A unified radio button component that can be used across different implementations ```kotlin @Composable fun RadioButton( selected: Boolean, modifier: Modifier = Modifier, enabled: Boolean = true, onClick: () -> Unit, selectedColor: Color = LocalAgentforceTheme.current.colors().accent1, unselectedColor: Color = LocalAgentforceTheme.current.colors().surfaceContainer3, offsetX: Dp = DEFAULT_RADIO_ICON_OFFSET_X, offsetY: Dp = DEFAULT_RADIO_ICON_OFFSET_Y, rowPadding: Dp = DEFAULT_ROW_PADDING, contentStartPadding: Dp = DEFAULT_CONTENT_START_PADDING, itemContent: @Composable ColumnScope.() -> Unit ) ``` ## SimpleRadioButton `@Composable fun SimpleRadioButton` A simplified radio button with just text content ```kotlin @Composable fun SimpleRadioButton( modifier: Modifier = Modifier, state: RadioButtonItemState, selected: Boolean, enabled: Boolean = true, onClick: () -> Unit, selectedColor: Color = LocalAgentforceTheme.current.colors().accent1, unselectedColor: Color = LocalAgentforceTheme.current.colors().surfaceContainer3, fontWeight: FontWeight = FontWeight.Normal, textColor: Color = if (enabled) { LocalAgentforceTheme.current.colors().onSurface1 } else { LocalAgentforceTheme.current.colors().surfaceContainer3 }, offsetX: Dp = DEFAULT_RADIO_ICON_OFFSET_X, offsetY: Dp = DEFAULT_RADIO_ICON_OFFSET_Y, rowPadding: Dp = DEFAULT_ROW_PADDING, contentStartPadding: Dp = DEFAULT_CONTENT_START_PADDING ) ``` ## Related Documentation - [AgentforceThemeManager](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-theme-manager-android.md) - [AgentforceColors](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-colors-android.md) - [AgentforceConversation](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-conversation-android.md) # Citations Apex Classes This page contains the reference material for citations in Apex. For a guide on using these classes, see [Get Started with Citations Apex](/docs/ai/agentforce/guide/citations.html). To generate inline citations via the Agent API, see [Agent API Examples](/docs/ai/agentforce/guide/agent-api-examples.html). ## GenAiCitationInput This class contains the data that an action returns to the Agentforce reasoning engine. The reasoning engine can then use this data if the citations service is called. | Property | Type | Description | | :-------- | :-------------------------------------------- | :------------------------ | | inputText | string | The data from the action. | | sources | [GenAiSourceReference](#genaisourcereference) | The source information. | ### GenAiSourceReference Represents a source of information for generating citations. | Property | Type | Description | | :------- | :---------------------------------------------------- | :------------------------------------ | | id | string | The ID of the source information. | | contents | [GenAiSourceContentInfo](#genaisourcecontentinfo) | The content of the source information | | metadata | [GenAiSourceReferenceInfo](#genaisourcereferenceinfo) | Metadata on the source information. | #### GenAiSourceContentInfo Represents specific content from a source that's being cited. | Property | Type | Description | | :--------- | :----- | :------------------------------------------------------------- | | fieldName | string | Not required. The name of the field from the source. | | objectName | string | Not required. The object that the source data originates from. | | content | string | The data from the source. | #### GenAiSourceReferenceInfo Represents metadata for a source reference. | Property | Type | Description | | :---------------------- | :----- | :------------------------------- | | link | string | A link to the source content. | | source_object_record_id | string | The ID for the source object. | | source_object_api_name | string | The API name for the source. | | label | string | The custom label for the source. | ## GenAiCitationOutput This class enables actions to directly provide citations for responses without calling the citations service through the Agentforce reasoning engine. This class closely resembles the output of the citations service. | Property | Type | Description | | :--------- | :------------------------------------------ | :------------------------- | | references | [GenAiCitedReference](#genaicitedreference) | The reference to a source. | ### GenAiCitedReference Represents a citation or reference to a source. | Property | Type | Description | | :------- | :-------------------------------------------------- | :------------------------- | | metadata | [GenAiCitedReferenceInfo](#genaicitedreferenceinfo) | The metadata for a source. | #### GenAiCitedReferenceInfo Represents metadata for a cited reference. | Property | Type | Description | | :---------------------- | :----- | :---------------------------------- | | link | string | A link to the cited source content. | | source_object_record_id | string | The ID for the source object. | | source_object_api_name | string | The API name for the source. | | label | string | The custom label for the source. | # Code Your Agent Using Its Agent Script File After you have the agent's authoring bundle in your DX project, either by generating it from scratch or retrieving it from your org, you customize the agent by coding its Agent Script file, which is the agent's blueprint. You can code the file directly in the VS Code editor, or use the Agentforce Vibes Extension to vibe code it. Vibe coding refers to using natural language prompts and letting Agentforce Vibes generate the actual code for you. ## Brief Overview of Agent Script Agent Script is the language for building Agentforce agents. It combines the flexibility of natural language instructions with the reliability of programmatic expressions for handling business rules. Agent Script provides all the advantages of access to a large language model (LLM), while also giving you ways to add more deterministic behaviors to your agent. In Agent Script, you use expressions to define if-then-else conditions, transitions, and other logic; set, modify, and compare variables; and select subagents and actions. You can build predictable, context-aware agent workflows that don’t rely on interpretation by an LLM. The Agent Script Language Server VS Code extension adds support for Agent Script, just like other Salesforce VS Code extensions provide language support for Apex, Lightning Web Components (LWC), and so on. As a result, when you open an Agent Script file in the VS Code editor, you see the colored syntax highlighting, visual cues (such as red squiggles) for syntax errors, internal validation, and so on. The Outline view in VS Code is also populated by a symbol tree based on the contents of the Agent Script file. See [Agent Script](https://developer.salesforce.com/docs/ai/agentforce/agent-script/agent-script.md) for more information about the language itself. Here's an example of a simple Agent Script file. ```agentscript system: instructions: "You are a friendly and empathetic agent that helps customers with their questions." messages: error: "Sorry, something went wrong." welcome: "Hello! How are you feeling today?" variables: isPremiumUser: mutable boolean = False description: "Indicates whether the user is a premium user." config: agent_name: "HelloWorldBot" access: default_agent_user: "hello@world.com" language: default_locale: "en_US" start_agent hello_world: description: "Respond to the user." reasoning: instructions: -> if @variables.isPremiumUser: | ask the user if they want to redeem their Premium points else: | ask the user if they want to upgrade to Premium service ``` ## Let's Code Enough with all these words, let's get coding already. Here's the high-level developer workflow: 1. In VS Code, open the agent's Agent Script file in the editor. Agent Script files are located in the `aiAuthoringBundles/` directory of your DX project's package directory. For example, if your authoring bundle's API name is `Local_Info_Agent` and you use the default package directory, open `force-app/main/default/aiAuthoringBundles/Local_Info_Agent/Local_Info_Agent.agent`. 1. Code the script file using the Agent Script language. See [Agent Script Tips](#agent-script-tips) for some information to get you started. 1. If you want to vibe code: 1. Open the Agentforce Vibes panel by clicking **Agentforce Vibes** (![Agentforce Vibes icon.](https://developer.salesforce.com/media/dx-vibecodey_icon.png '{"class": "image-icon-sm"}') icon) in the Activity Bar. 1. At the bottom of the panel, click **Manage Agentforce Rules, Workflows, Hooks & Skills** (⚖️ icon) and then the **Skills** tab. 1. Ensure that these three skills are enabled: `developing-agentforce`, `testing-agentforce`, and `observing-agentforce`. **warning:** Enabling and using the Agentforce Vibes skills for Agent Script can rapidly increase your token consumption. 1. Enter a prompt in the Agentforce Vibes chat box, such as _Review all the agent instructions and improve them for focus and conciseness_. See [Vibe Coding Information and Sample Prompts](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-nga-script.md#vibe-coding-information-and-sample-prompts) for more sample prompts and information about these Agentforce skills. 1. Periodically [validate the Agent Script file](#validate-the-agent-script-file) to ensure that it compiles. 1. Periodically [preview the agent from its Agent Script file](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-nga-preview.md) to see how it's working. This screenshot shows VS Code ready to code an Agent Script file called `Local_Info_Agent.agent`; the highlighted parts are described after the screenshot. The custom layout of the VS Code panels is similar to how the Agentforce Builder UI in your org looks. ![VS Code showing open DX project on the left, an open Agent Script file in the middle editor, and Agentforce Vibes on the right with a vibe coding prompt ready to go.](https://developer.salesforce.com/media/dx-nga-vibe-coding-3.png '{"class": "image-full"}') - `(1)` shows the `agentforcedx` DX project open in the VS Code's file explorer. - `(2)` shows the location of the `Local_Info_Agent` authoring bundle in the DX project package directory. The authoring bundle includes the `Local_Info_Agent.agent` Agent Script file. - `(3)` shows that the Outline view displays a symbol tree of the Agent Script file, with blocks such as `system`, `config`, `variables`, `subagent`, and so on. - `(4)` shows the open `Local_Info_Agent.agent` Agent Script file, with colored syntax highlighting. - `(5)` shows Agentforce Vibes. - `(6)` shows a vibe coding prompt in the chat box, ready to be executed. - `(7)` shows the icon to enable the Agentforce Vibes skills for working with Agent Script. ## Agent Script Tips You should already have some basic information in your Agent Script file, either because you generated its authoring bundle from an agent spec YAML file or you retrieved an authoring bundle from your org. This section doesn't provide comprehensive information about how to code your script file, but it provides some tips to get you going. See the [Agent Script](https://developer.salesforce.com/docs/ai/agentforce/agent-script/agent-script.md) documentation for more information and examples. - Learn about the characteristics of the Agent Script language itself, such as how to access resources, the language format and indentation, using expressions, and so on. - Familiarize yourself with the blocks that make up an Agent Script file. For example, the `system` block contains general agent instructions, the `config` block contains basic agent configuration, and the `subagent` block contains all the information associated with subagents, such as instructions, logic, and actions. - Add the username of the Salesforce user that runs the agent to the `default_user_agent` parameter of the `config` block. You can create this user in your org using Setup or Agentforce Builder, or use the `org create agent-user` CLI command. See [Create the Default Agent User](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-set-up-env.md#create-the-default-agent-user). - Start with basic agent design, such as defining the required subagents and the associated actions. Don't worry if you haven't yet created the Apex classes, flows, and prompt templates that implement the actions. Simply reference them in your script file for now, as if they actually exist. When you later preview this agent, you can use simulated mode to mock the actions. If you do have existing Apex classes and flows that you want to use to implement actions, then go ahead and use them in the Agent Script file. - Determine when you want to allow the LLM to make its own reasoning decision and when you want the agent to execute deterministically. - Design the flow of control, such as what happens when the user makes its first request to the agent, what additional subagents might be required, and how to transition between subagents. - Check out [this collection of easy-to-digest Agent Script examples](https://github.com/trailheadapps/agent-script-recipes). Each recipe demonstrates how to build a specific agent behavior in the fewest lines of script possible while following best practices. From `Hello World` interactions to sophisticated agent transitions, there's a recipe for that! ## Vibe Coding Information and Sample Prompts Agentforce Vibes, and other AI assistants such as Claude Code, use skills to help you vibe code your Agent Script file. Skills are modular instruction sets that extend Agentforce Vibes' capabilities for specific tasks. Each skill packages detailed guidance, workflows, and optional resources that Agentforce Vibes loads only when relevant to your request. Skills load on-demand so they don't consume context when you work on unrelated tasks. The Salesforce skills are publicly available in the [sf-skills](https://github.com/forcedotcom/sf-skills/tree/main/skills) GitHub repo. Skills for the agentic development lifecycle contain the word `agentforce`. These skills help you build, modify, debug and deploy Agentforce agents using Agent Script. They also provide comprehensive testing capabilities, including automated utterance derivation from agent subagents, preview-based smoke testing, trace analysis, and an iterative fix loop for identified issues. Here are some prompts to get you started if you decide to use Agentforce Vibes to vibe code your Agent Script file. - _Change the display name to Local Info Agent._ - _Add a new subagent for updating the customer information if it's changed. Use an existing flow for the action, if you find one that's suitable. Otherwise, create a new flow._ - _Add an action to the identify_customer subagent for identifying a customer based on their cell phone._ - _Review all the agent instructions and improve them for focus and conciseness._ ## Validate the Agent Script File Validating the Agent Script file ensures that it compiles successfully so that you can publish it to your org, and eventually activate it so your users can start using it. **tip:** Because an _agent_ is defined by its _authoring bundle_, this documentation and the Agentforce DX tools use the two terms interchangeably. For example, the CLI command discussed in this topic uses the term _authoring bundle_, such as `agent validate authoring-bundle`. However, the equivalent VS Code command uses the term _agent_, such as **AFDX: Validate This Agent**. ### Use VS Code to Validate 1. In VS Code, open the agent's Agent Script file, which is located in the `aiAuthoringBundles/` directory of your package directory. For example, if your agent's API name is `Local_Info_Agent` and you use the default package directory in your DX project, open `force-app/main/default/aiAuthoringBundles/Local_Info_Agent/Local_Info_Agent.agent`. 1. Right-click the file in the editor and choose **AFDX: Validate This Agent**. You can also right-click from the script file in the explorer panel or choose the command from the Command Palette. 1. A progress bar in the lower right corner notifies you of the status of the validation. If the validation fails, see the **Problems** tab for the list of syntax errors, a brief description of the error, and the location in the Agent Script file where the error occurred. This simple example shows that there's a typo for the description of the `start_agent` block. ![VS Code showing Agent SCript file with a type and the validation errors in the Problems tab.](https://developer.salesforce.com/media/dx-script-validation-2.png '{"class": "image-full"}') Fix the errors and then retry the validation. ### Use a CLI Command to Validate 1. From VS Code's integrated terminal, run this command from your DX project: ```bash sf agent validate authoring-bundle ``` The command searches the DX project for authoring bundles and provides a list of their API names that you can choose from. You can also specify the Agent Script file you want to validate by passing its API name to the `--api-name` flag. 1. The command output displays whether the validation failed or succeeded. If the validation fails, the output displays the list of syntax errors, a brief description of the error, and the location in the Agent Script file where the error occurred. Fix the errors and then retry the validation. For more details on the `validate` command, see [`agent validate authoring-bundle`](https://developer.salesforce.com/docs/platform/salesforce-cli-reference/guide/cli_reference_agent_validate_authoring-bundle.html) in the Salesforce CLI Command Reference. ## Next Steps - [Preview and Debug an Agent](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-nga-preview.md) - [Publish an Authoring Bundle to Your Org](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-nga-publish.md) ## See Also - [Get Started with Agent Script](https://developer.salesforce.com/docs/ai/agentforce/agent-script/agent-script.md) - [Agent Script Recipes](https://github.com/trailheadapps/agent-script-recipes) - [Agent Script Recipes Documentation](https://developer.salesforce.com/sample-apps/agent-script-recipes) - [Agentforce Vibes Extension](https://developer.salesforce.com/docs/platform/einstein-for-devs/guide/einstein-overview.html) - [Skills](https://developer.salesforce.com/docs/platform/einstein-for-devs/guide/skills.html) # Collect and Store Customer Information with Ask For (Beta) Use `ask for` inside reasoning instructions to collect information from the customer, one field at a time, and store each response in a variable. For every `ask for` instruction, Agentforce prompts the customer for a single value, saves the response to the specified variable, and then routes back to the same subagent to collect the next value. The agent routes to the same subagent until every `ask for` variable is populated. Agentforce validates responses against the variable's type. For example, if a variable expects an email address and the customer enters something that isn't a valid email, the agent asks again until it receives a valid value. **When to use**: Use `ask for` when your subagent needs structured input, like an intake form, before it can transition to the next step or run a downstream action. ```bash #This subagent collects information from the user. When all the information is collected, the subagent transitions to another subagent subagent patient_intake: description: "Gather the patient's street address, city, and email — one field at a time." reasoning: instructions: -> ask for @variables.patient_address_line1 instructions: |Please provide the first line of your address (house/building number and street name only). ask for @variables.patient_city instructions: |Please provide your town or city. ask for @variables.patient_email instructions: |Please provide your email address. if @variables.patient_email is not None: transition to @subagent.patient_symptoms subagent patient_symptoms: # This subagent demonstrates a transition target; it doesn't do anything label: "patient_symptoms" description: | Collects the patient symptoms reasoning: instructions: -> | Ask the customer about their symptoms ``` # Collect Customer Information to Create a Record Reliably collect customer input across multiple turns, then create a Salesforce record. Ensure that the agent collects all required information before creating the record. This example ensures the agent: - Creates a record only **after** collecting **all** the required information. - Reliably stores all provided information, even after multiple turns. - Creates only one (not multiple) record per conversation. - Confirms that a record creation actually happened. ### The Problem A common agent pattern is to collect a lot of information from a customer, ask clarifying questions, verify the information is correct, and then create a Salesforce record. During multiple turns and long conversations, some agents can drop captured values, re-ask for information they already have, create half-filled records, or falsely confirm a record creation. ### The Solution One solution is to create two subagents. (One subagent)[#add-the-lead-gather-subagent] gathers customer information and stores the information in variables. The subagent's `after_reasoning` block checks whether all variables have values - if so, it runs the action to create the record. If the record ID is returned (indicating the record was created), the `after_reasoning` block transitions to a second subagent, which reports the record creation to the customer. ## Create a Flow to Create the Lead Record from Fields Create a flow that creates a lead record with the customer-provided fields. ![Flow overall](https://developer.salesforce.com/media/agent-script/collect-example_flow.jpg '{"class": "image-lg"}') #### Step 1 - Create the Autolaunched Flow 1. From the app launcher, enter flows, and then select **Flows**. 2. Click **New Flow**. 3. Select the **Autolaunched** category, and then select **Autolaunched Flow (No Trigger)**. #### Step 2 - Create the Flow Variables Expand the toolbox (button on the far left). Using the **New Resource** button, create six variables defined as follows. Match the API names exactly — they map to the agent action's inputs and outputs. | Resource Type | API Name | Data Type | Available for input | Available for output | | ------------- | -------------- | --------- | ------------------- | -------------------- | | Variable | `Company` | Text | **select** | **don't** select | | Variable | `Email` | Text | **select** | **don't** select | | Variable | `FirstName` | Text | **select** | **don't** select | | Variable | `LastName` | Text | **select** | **don't** select | | Variable | `Phone` | Text | **select** | **don't** select | | Variable | `leadRecordId` | Text | **don't** select | **select** | Click Save. Name the flow **Create Lead by Field** and ensure the flow's API name is `Create_Lead_by_Field`. **important:** We use this flow name later in the agent script. It needs to match, otherwise you'll have to edit your script by hand. #### Step 3 - Get Existing Lead Before creating a new lead record, we'll use the provided email and company name to see if that lead record exists. 1. Add a Get Records Element. 1. For the label, enter **Get Existing Lead**. 2. For the object, select **Lead**. 2. Under Filter Lead Records, select **All Conditions Are Met (AND)**, then enter these values: | Field | Operator | Value | | ------- | -------- | ------- | | Email | Equals | Email | | Company | Equals | Company | 3. Under Sort Lead Records, for Sort Order, select **Not Sorted**. 4. Under How Many Records to Store, select **Only the first record**. 5. Under How to Store Record Data, select **Choose fields and let Salesforce do the rest**. 6. Under Select Lead Fields to Store in Variable, leave the first Field set to **Id**. You don't need to add additional fields — the flow only uses the lead Id to detect an existing record. ![get records element to get matching record](https://developer.salesforce.com/media/agent-script/getExistingLead.jpg '{"class": "image-lg"}') #### Step 4 - Check Whether the Lead Exists Branch the flow based on whether Get Existing Lead returned a matching lead. 1. Add a Decision element after **Get Existing Lead**. 1. For the label, enter **Lead Exists?**. The API Name auto-fills as `Lead_Exists`. 2. Under Select Decision Logic, select **Define Manually (Default)**. 3. Under Outcomes, configure the **Yes** outcome to run when a matching Lead was found. 1. For Outcome Label, enter **Yes**. 2. For Outcome API Name, enter **Yes_Reuse**. 3. For Condition Requirements to Execute Outcome, select **All Conditions Are Met (AND)**. 4. Add this condition: | Resource | Operator | Value | | --------------------------- | -------- | ----- | | Get Existing Lead > Lead ID | Is Null | False | 4. Select the default tab and rename it to **No**. The flow follows the No path when no matching lead exists. ![decision element to see if the lead exists](https://developer.salesforce.com/media/agent-script/DecisionLeadExists.jpg '{"class": "image-lg"}') #### Step 5 - Assign Existing Lead Id On the **Yes** path, you'll copy the existing Lead's Id into `leadRecordId` so the flow returns the same value whether the lead was found or newly created. 1. On the **Yes** outcome from **Lead Exists?**, add an Assignment element. 1. For the label, enter **Assign Existing LeadId**. The API Name auto-fills as `Assign_Existing_LeadId`. 2. Under Set Variable Values, add this assignment: | Variable | Operator | Value | | -------------- | -------- | --------------------------- | | `leadRecordId` | Equals | Get Existing Lead > Lead ID | 2. Connect the Assignment element to its own **End** element, which terminates the decision's **Yes** path. ![decision element no path](https://developer.salesforce.com/media/agent-script/DecisionLeadYes.jpg '{"class": "image-lg"}') #### Step 6 - Add `LeadExampleAgent` to the LeadSource Picklist To make sure your agent gets credit for this lead, we'll add `LeadExampleAgent` to the possible lead source values. 1. From Setup, click **Object Manager**. 2. Select **Lead**, then click **Fields & Relationships**. 3. Click **Lead Source**. 4. Under Account/Lead Source Picklist Values, click **New**, add `LeadExampleAgent`. 5. Click **Save**. ![decision element to see if the lead exists](https://developer.salesforce.com/media/agent-script/LeadExample.jpg '{"class": "image-md"}') #### Step 7 - Create the Lead Add an element to create the lead, mapping the agent action's values to the variables [you created earlier](#step-2---create-the-flow-variables). **Match the API names exactly** — they map to the agent action's inputs. 1. On the **No** outcome from **Lead Exists?**, add a Create Records element. 1. For the label, enter **Create Lead**. The API Name auto-fills as `Create_Lead`. 2. For How to set record field values, select **Manually**. 3. Under Create a Record of This Object, for Object, select **Lead**. 4. Under Set Field Values for the lead, add a row for each of these fields and map it to the indicated variable. | Field | Value | | ----------- | ------------------ | | Company | `Company` | | Email | `Email` | | First Name | `FirstName` | | Last Name | `LastName` | | Lead Source | `LeadExampleAgent` | | Phone | `Phone` | 5. Select **Manually assign variables (advanced)**. 6. Under Store Lead ID in Variable, for Variable, select **`leadRecordId`**. 7. Leave **Check for Matching Records** disabled — the **Lead Exists?** decision already handles the duplicate check. 8. Click **Save**. ![decision element to see if the lead exists](https://developer.salesforce.com/media/agent-script/CreateLead.jpg '{"class": "image-lg"}') #### Step 8 - Handle a Create Lead Fault If the Create Lead element fails at runtime (for example, a validation rule rejects the record), the flow returns a lead Id anyway unless you explicitly clear it. Add a fault path that resets `leadRecordId` so the agent's `after_reasoning` gate treats the create as unsuccessful. 1. Hover over the **Create Lead** element so the three dots appear. 2. Click the three dots and select **Add Fault Path**. 3. On the fault path, add an Assignment element. 1. For the label, enter **Clear LeadId On Fault**. The API Name auto-fills as `Clear_LeadId_On_Fault`. 4. Under Set Variable Values, add this assignment: | Variable | Operator | Value | | -------------- | -------- | -------------------------- | | `leadRecordId` | Equals | Blank Value (Empty String) | 5. Connect the Assignment element to an **End** element to terminate the fault path. ![decision element to see if the lead exists](https://developer.salesforce.com/media/agent-script/faultpath.jpg '{"class": "image-lg"}') #### Step 9 - Test the Flow Test the flow. 1. In Flow Builder, click **Debug**. 2. Enter test values for `Company`, `Email`, `FirstName`, `LastName`, `Phone`. 3. Click **Run** and verify a lead is created (or the existing one is returned). Notice that the lead source is `LeadExampleAgent`. #### Step 10 - Activate Your Flow Click **Activate** in the upper right. ## Create Your Agent You can create a new agent using the Agentforce Service Agent template, or you can add these subagents and variables to an existing agent. ### Step 1 - Create or Reuse an Agent For this example, you can add the two subagents to an existing agent. Or, you can create a service agent from a template. To create a service agent: 1. In the App menu, enter and select Agentforce Builder. 2. Select **New Agent**, then select **Agentforce Service Agent**. 3. Give your agent a name, such as Lead Gather Example. 4. Accept **New User** to create a new agent user. 5. Switch to Script view (click the ``toggle in the upper left) ### Step 2 - Create the Variables The agent uses variables to store customer input during the information-collection turns. The agent also needs a variable to hold the lead ID that the action returns. 1. Copy and paste these variables into your agent's existing `variables` block. ```agentscript # Variables from Lead Gather example # variables: lead_id: mutable string = "" description: "Stores the record ID of the Lead created for the prospect." visibility: "Internal" company: mutable string = "" description: "Stores the prospect's company name." visibility: "Internal" email: mutable string = "" description: "Stores the prospect's email address." visibility: "Internal" first_name: mutable string = "" description: "Stores the prospect's first name." visibility: "Internal" last_name: mutable string = "" description: "Stores the prospect's last name." visibility: "Internal" phone: mutable string = "" description: "Stores the prospect's phone number." visibility: "Internal" ``` 2. Save your agent. **note:** The variable defaults matter. Our agent uses `""` to mean "not yet captured." ## Add the Lead Gather Subagent The Lead Gather subagent asks for the required information and captures any relevant information that is provided. The `after_reasoning` block, which runs after every reasoning loop, checks if all variables are populated. Once **all** the variables have values (this might take many conversational turns), the agent runs the `Create Lead_by_Field` action to create the lead. If the action returns a lead record ID, the `after_reasoning` section transitions to the lead confirmation subagent. 1. Copy this subagent script and paste the script at the end of your existing agent's script. If you followed the flow naming conventions, this subagent correctly uses the Create Lead by Field action. ```agentscript subagent lead_gather: label: "Lead Gather" description: "Collects prospect details and creates a lead." reasoning: instructions: -> | Ask for first name, last name, email, company, and phone number in one message. | Use {!@actions.capture_details} whenever the prospect supplies details. | Ask only for any remaining missing details. | Do not claim that the lead was created or that a meeting was scheduled. actions: capture_details: @utils.setVariables # this action is available ONLY if the lead hasn't been created yet this session # That is, the customer can't create a second unique lead in the same session available when @variables.lead_id == "" with company = ... with email = ... with first_name = ... with last_name = ... with phone = ... # after_reasoning is run after every reasoning session after_reasoning: # if we DON'T have all the variables we need, don't run the action if @variables.company != "" and @variables.email != "" and @variables.first_name != "" and @variables.last_name != "" and @variables.phone != "" and @variables.lead_id == "": run @actions.Create_Lead_by_Field with Company = @variables.company with Email = @variables.email with FirstName = @variables.first_name with LastName = @variables.last_name with Phone = @variables.phone set @variables.lead_id = @outputs.leadRecordId # if we DID create a lead, transition to the Lead Confirmation subagent if @variables.lead_id != "": transition to @subagent.lead_confirmation actions: Create_Lead_by_Field: description: "Creates a Lead record from the prospect details captured in the conversation." label: "Create Lead by Field" require_user_confirmation: False include_in_progress_indicator: True target: "flow://Create_Lead_by_Field" inputs: "Company": string description: "The prospect's company name." label: "Company" is_required: True is_user_input: False "Email": string description: "The prospect's email address." label: "Email" is_required: True is_user_input: False "FirstName": string description: "The prospect's first name." label: "First Name" is_required: True is_user_input: False "LastName": string description: "The prospect's last name." label: "Last Name" is_required: True is_user_input: False "Phone": string description: "The prospect's phone number." label: "Phone" is_required: True is_user_input: False outputs: "leadRecordId": string description: "The Salesforce record ID of the newly created Lead." label: "Lead Record Id" is_displayable: False filter_from_agent: True ``` 2. Add these lines to the agent router, lining up the action with the other agent router actions. ```agentscript go_to_lead_gather: @utils.transition to @subagent.lead_gather ``` 3. Save your agent. **note:** You'll see an error that the lead_gather subagent doesn't exist - we'll fix that problem in the next step. ![decision element to see if the lead exists](https://developer.salesforce.com/media/agent-script/agentrouter.jpg '{"class": "image-lg"}') ## Add the Lead Confirmation Subagent This subagent tells the customer that a lead has been created. The agent router **doesn't** have access to this subagent. This subagent is only called from the `after_reasoning` block of the create lead subagent, which is only available if the Create Lead by Field Action returned a lead Id. These safeguards ensure the agent never falsely confirms a lead creation to the customer. 1. Copy this subagent script and paste the script at the end of your existing agent's script. ```agentscript subagent lead_confirmation: label: "Lead Confirmation" description: "Confirms that the lead was successfully created." reasoning: instructions: -> | Confirm that the prospect's details were captured successfully. | Explain that a team member will follow up to arrange a meeting. ``` 2. Save your agent. ## Grant Agent User Permissions Your agent user needs permission to read and create leads. 1. From **Setup**, in the Quick Find box, enter and select **Permission Sets**. 2. Click to open your agent user's permission set. 3. Click to open **Object Settings**. 4. Scroll down, then click to open **Leads**. 5. Click **Edit**. 6. Under Object Permissions, for Read and Create, select **Enabled**. 7. Click **Save**. ![the read and create permissions selected](https://developer.salesforce.com/media/agent-script/createLeadPermissions.jpg '{"class": "image-md"}') **note:** Always give your agent user the fewest permissions it needs to do its job. For more information about service agent permissions, see [(Help:) Best Practices for Agent User Permissions](https://help.salesforce.com/s/articleView?id=ai.agent_user.htm&type=5). ## Test Your Agent Preview the agent and test three scenarios: | Scenario | Customer Utterance | Expected Result | | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | Happy path — all fields in one message. | `Hi, I'd like to schedule a meeting to learn more about your product.` Then when asked: `I'm Casey Rivera, casey.rivera@example.com, Northwind Labs, 415-555-0142.` | The agent transitions to `lead_confirmation`, creates the lead, and confirms the lead creation. | | No duplicate record created. | Repeat the happy path with the same email and company. | The agent returns the **same** Lead ID as before. No duplicate lead record is created. | | Partial-info gate — only some fields. | `Hi, I want to book a meeting.` Then when asked for information, provide only one answer per turn. | The agent keeps asking for the missing information. Once all information is provided, the agent creates the lead and confirms with the customer. | # Color Token Reference This page lists every color token the Agentforce Android SDK exposes for [theming](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guides/android/agentforce-mobile-sdk-android-branding-theming.md), with its default value in both light and dark mode. There are **271 color tokens** in total: **47 foundation tokens** and **224 component-level tokens** across **50 component groups**. Groups and token order match the SDK, so this page reads top-to-bottom the same way the components are laid out. ## How tokens resolve The palette has two layers: 1. **Foundation tokens** (from the Salesforce design system): `surface1`, `accent1`, `onSurface1`, `border1`, and so on. These carry explicit light and dark values. 2. **Component tokens**: every UI element has its own token — for example `titleBarBackground`, `sendButtonEnabledBackground`, `carouselSurface`. Each one falls back to a foundation token by default, so changing one component never affects another that happens to share the same foundation color. Each component token resolves its default in one of three ways: - **Alias** — falls back to a foundation token (shown in the **Resolves to** column). Its default light and dark values are that foundation token's values. - **Fixed literal** — a single color that's identical in light and dark. - **Per-mode literal** — distinct light and dark colors. Override any token — foundation or component — with `withOverrides(...)` or `AgentforceThemeOverrides`. See [Theming](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guides/android/agentforce-mobile-sdk-android-branding-theming.md) for usage. ## Foundation tokens The design-system base palette. Every component token below ultimately resolves to one of these (unless it's a fixed or per-mode literal). Override these to re-skin the whole UI at once. | Token (`AgentforceColorToken`) | Key | Light | Dark | | ------------------------------ | -------------------------- | --------- | --------- | | `Surface1` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `Surface2` | `surface2` | `#F3F3F3` | `#302D2D` | | `SurfaceContainer1` | `surfaceContainer1` | `#F3F3F3` | `#2E2E2E` | | `SurfaceContainer2` | `surfaceContainer2` | `#F5F5F5` | `#777777` | | `SurfaceContainer3` | `surfaceContainer3` | `#D8D8D8` | `#BEBEBE` | | `SurfaceContainerInverse1` | `surfaceContainerInverse1` | `#1F1F1F` | `#FFFFFF` | | `OnSurface1` | `onSurface1` | `#000000` | `#FFFFFF` | | `OnSurface2` | `onSurface2` | `#222222` | `#E8E8E8` | | `OnSurface3` | `onSurface3` | `#939393` | `#E0E0E0` | | `OnSurfaceInverse1` | `onSurfaceInverse1` | `#FFFFFF` | `#1D1D21` | | `Border1` | `border1` | `#DEDFE1` | `#6E6D6D` | | `Border2` | `border2` | `#DADCE0` | `#5F6368` | | `Accent1` | `accent1` | `#0170CB` | `#008AF7` | | `Accent2` | `accent2` | `#F2F2F2` | `#777777` | | `Accent3` | `accent3` | `#D6E6FF` | `#3A3A3A` | | `AccentContainer1` | `accentContainer1` | `#E9F5FF` | `#0077D9` | | `AccentContainer2` | `accentContainer2` | `#1A73E8` | `#5E9BFF` | | `OnAccent1` | `onAccent1` | `#FFFFFF` | `#FFFFFF` | | `BorderAccent1` | `borderAccent1` | `#0084FF` | `#4285F4` | | `BorderAccent2` | `borderAccent2` | `#1A73E8` | `#5E9BFF` | | `Error1` | `error1` | `#BA0517` | `#E24857` | | `ErrorContainer1` | `errorContainer1` | `#FCE8E6` | `#FEB8AB` | | `ErrorContainer2` | `errorContainer2` | `#EA4335` | `#9B000F` | | `OnError1` | `onError1` | `#EA4335` | `#9B000F` | | `BorderError1` | `borderError1` | `#BA0517` | `#9B000F` | | `Success1` | `success1` | `#34A853` | `#34A853` | | `SuccessContainer1` | `successContainer1` | `#E6F4EA` | `#2D3B2F` | | `SuccessContainer2` | `successContainer2` | `#34A853` | `#34A853` | | `OnSuccess1` | `onSuccess1` | `#34A853` | `#81C995` | | `BorderSuccess1` | `borderSuccess1` | `#34A853` | `#34A853` | | `Disabled1` | `disabled1` | `#9AA0A6` | `#5F6368` | | `DisabledContainer1` | `disabledContainer1` | `#EBEBEB` | `#2D2D30` | | `DisabledContainer2` | `disabledContainer2` | `#E8EAED` | `#484848` | | `OnDisabled1` | `onDisabled1` | `#898A8D` | `#C1C1C1` | | `OnDisabled2` | `onDisabled2` | `#DADADA` | `#666666` | | `BorderDisabled1` | `borderDisabled1` | `#E8EAED` | `#484848` | | `Warning1` | `warning1` | `#F9AB00` | `#FBBC04` | | `WarningContainer1` | `warningContainer1` | `#FEF7E0` | `#3B3426` | | `OnWarning1` | `onWarning1` | `#8C4B02` | `#F9AB00` | | `Info1` | `info1` | `#1A73E8` | `#5E9BFF` | | `InfoContainer1` | `infoContainer1` | `#E8F0FE` | `#2A3441` | | `Information1` | `information1` | `#1A73E8` | `#5E9BFF` | | `InformationContainer1` | `informationContainer1` | `#E8F0FE` | `#2A3441` | | `BrandBase90` | `brandBase90` | `#E3F2FD` | `#2A3441` | | `BrandBase50` | `brandBase50` | `#0176D3` | `#5E9BFF` | | `ErrorBase50` | `errorBase50` | `#EA4335` | `#E24857` | | `CloudBlue60` | `cloudBlue60` | `#0D9DDA` | `#1AB9FF` | ## Component tokens Every UI element has its own token, grouped below by component. ### Chat scaffold The root chat surface. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ----------- | --------- | --------- | | `ChatBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | ### Title bar / navigation The conversation header (title, icons, divider). | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------ | --------- | --------- | | `TitleBarBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `TitleBarTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `TitleBarIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `TitleBarDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | ### Input bar The message composer row. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | -------------------------------- | ---------------- | --------- | --------- | | `InputBarBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `InputBarListeningBackground` | `accent3` | `#D6E6FF` | `#3A3A3A` | | `InputBarFieldBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `InputBarFieldBorderColor` | `onSurface3` | `#939393` | `#E0E0E0` | | `InputBarTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `InputBarPlaceholderColor` | per-mode literal | `#757575` | `#D2D2D2` | | `InputBarIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `InputBarTopDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | | `InputBarCursorColor` | `accent1` | `#0170CB` | `#008AF7` | | `InputBarAttachmentDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | ### Send button The send-message button. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------- | --------- | --------- | | `SendButtonEnabledBackground` | `accent1` | `#0170CB` | `#008AF7` | | `SendButtonDisabledBackground` | `onDisabled1` | `#898A8D` | `#C1C1C1` | | `SendButtonIconTint` | `onAccent1` | `#FFFFFF` | `#FFFFFF` | ### Voice / stop-listening button The voice-entry (waveform) button in the input bar. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------ | --------- | --------- | | `VoiceButtonBackground` | `onSurface1` | `#000000` | `#FFFFFF` | | `VoiceButtonBorder` | `onSurface1` | `#000000` | `#FFFFFF` | | `VoiceButtonAccentColor` | `accent1` | `#0170CB` | `#008AF7` | ### Agent avatar The agent avatar in the chat feed. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ---------------- | --------- | --------- | | `AgentAvatarBackground` | `accent3` | `#D6E6FF` | `#3A3A3A` | | `AgentAvatarIconTint` | `accent1` | `#0170CB` | `#008AF7` | | `AgentAvatarLiveBackground` | per-mode literal | `#05628A` | `#FFFFFF` | | `AgentAvatarLiveIconTint` | `accent3` | `#D6E6FF` | `#3A3A3A` | ### Agent message Agent name and message text. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------ | --------- | --------- | | `AgentMessageNameColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `AgentMessageTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | ### User message bubble The end user's message bubble. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------ | --------- | --------- | | `UserMessageBubbleBackground` | `accentContainer1` | `#E9F5FF` | `#0077D9` | | `UserMessageBubbleTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `UserMessageStatusColor` | `onSurface2` | `#222222` | `#E8E8E8` | | `UserMessageErrorColor` | `error1` | `#BA0517` | `#E24857` | ### Chat response / reply button Suggested reply and chat-response buttons. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | -------------------------------------- | ------------- | --------- | --------- | | `ChatResponseButtonBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `ChatResponseButtonTextColor` | `accent1` | `#0170CB` | `#008AF7` | | `ChatResponseButtonDisabledBackground` | `onDisabled2` | `#DADADA` | `#666666` | | `ChatResponseButtonDisabledTextColor` | `onDisabled1` | `#898A8D` | `#C1C1C1` | | `ChatResponseButtonPrimaryBackground` | `accent1` | `#0170CB` | `#008AF7` | | `ChatResponseButtonPrimaryTextColor` | `onAccent1` | `#FFFFFF` | `#FFFFFF` | ### Message action buttons Thumbs up / down / copy row under a message. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------- | ------------ | --------- | --------- | | `MessageActionIconActiveTint` | `accent1` | `#0170CB` | `#008AF7` | | `MessageActionIconInactiveTint` | `onSurface3` | `#939393` | `#E0E0E0` | ### Feedback modal The "why wasn't this helpful?" feedback sheet. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ---------------------------------- | -------------------- | --------- | --------- | | `FeedbackBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `FeedbackTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `FeedbackBorderColor` | `border1` | `#DEDFE1` | `#6E6D6D` | | `FeedbackButtonBackground` | `accent1` | `#0170CB` | `#008AF7` | | `FeedbackButtonDisabledBackground` | `disabledContainer1` | `#EBEBEB` | `#2D2D30` | | `FeedbackButtonTextColor` | `onAccent1` | `#FFFFFF` | `#FFFFFF` | | `FeedbackButtonDisabledTextColor` | `onDisabled1` | `#898A8D` | `#C1C1C1` | ### Toast The four toast status styles (shared with iOS). | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `ToastInfoBackground` | `infoContainer1` | `#E8F0FE` | `#2A3441` | | `ToastInfoForeground` | `info1` | `#1A73E8` | `#5E9BFF` | | `ToastSuccessBackground` | `successContainer1` | `#E6F4EA` | `#2D3B2F` | | `ToastSuccessForeground` | `onSuccess1` | `#34A853` | `#81C995` | | `ToastWarningBackground` | `warningContainer1` | `#FEF7E0` | `#3B3426` | | `ToastWarningForeground` | `onWarning1` | `#8C4B02` | `#F9AB00` | | `ToastErrorBackground` | `errorContainer1` | `#FCE8E6` | `#FEB8AB` | | `ToastErrorForeground` | `onError1` | `#EA4335` | `#9B000F` | ### Modal sheet More menu, multi-modal sheet, action list, agent selector. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | -------------------------------- | ------------ | --------- | --------- | | `ModalSheetBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `ModalSheetTitleColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `ModalSheetItemTextColor` | `onSurface2` | `#222222` | `#E8E8E8` | | `ModalSheetItemIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `ModalSheetDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | | `ModalSheetDoneButtonBackground` | `accent1` | `#0170CB` | `#008AF7` | | `ModalSheetDoneButtonTextColor` | `onAccent1` | `#FFFFFF` | `#FFFFFF` | ### Inline chat error Error shown inline inside an agent response. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ----------------- | --------- | --------- | | `MessageErrorBackground` | `errorContainer1` | `#FCE8E6` | `#FEB8AB` | | `MessageErrorTextColor` | `error1` | `#BA0517` | `#E24857` | ### Launcher The floating launcher entry point. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ---------------- | --------- | --------- | | `LauncherBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `LauncherInputBorderColor` | `onSurface3` | `#939393` | `#E0E0E0` | | `LauncherIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `LauncherTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `LauncherUnreadDotColor` | `accent1` | `#0170CB` | `#008AF7` | | `LauncherFlashBackground` | `accent3` | `#D6E6FF` | `#3A3A3A` | | `LauncherIconTileTint` | `accent1` | `#0170CB` | `#008AF7` | | `LauncherPlaceholderColor` | per-mode literal | `#757575` | `#D2D2D2` | ### Recommended utterance Suggested-utterance chips and their list. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ---------------- | --------- | --------- | | `UtteranceBackground` | per-mode literal | `#ECF5FE` | `#3A3A3A` | | `UtteranceTextColor` | `accent1` | `#0170CB` | `#008AF7` | | `UtteranceIconTint` | `accent1` | `#0170CB` | `#008AF7` | | `UtteranceListLabelColor` | `onSurface2` | `#222222` | `#E8E8E8` | | `UtteranceListBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | ### Carousel The horizontal card carousel. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------ | --------- | --------- | | `CarouselSurface` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `CarouselItemBorderColor` | `accent1` | `#0170CB` | `#008AF7` | | `CarouselTitleColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `CarouselDotSelectedColor` | `accent1` | `#0170CB` | `#008AF7` | | `CarouselDotUnselectedColor` | `onSurface3` | `#939393` | `#E0E0E0` | | `CarouselFadeOverlayColor` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `CarouselPlaceholderTint` | `onSurface3` | `#939393` | `#E0E0E0` | ### Source / citation Citation chips, list, and external link. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ---------------------------------- | ------------------- | --------- | --------- | | `CitationBackground` | `surfaceContainer1` | `#F3F3F3` | `#2E2E2E` | | `CitationTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `CitationIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `CitationListBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `CitationDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | | `CitationExternalLinkDefaultColor` | fixed literal | `#4892E7` | `#4892E7` | ### Rich link Rich link preview card. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `RichLinkBackground` | `surfaceContainer2` | `#F5F5F5` | `#777777` | | `RichLinkImageBackground` | `surfaceContainer2` | `#F5F5F5` | `#777777` | | `RichLinkPlaceholderTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `RichLinkTitleColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `RichLinkUrlColor` | `onSurface2` | `#222222` | `#E8E8E8` | ### Web link Inline web link chip. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `WebLinkBackground` | `surfaceContainer2` | `#F5F5F5` | `#777777` | | `WebLinkTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `WebLinkFaviconTint` | `onSurface3` | `#939393` | `#E0E0E0` | ### Record info Record info card. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `RecordInfoBackground` | `surfaceContainer1` | `#F3F3F3` | `#2E2E2E` | | `RecordInfoTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `RecordInfoLabelColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `RecordInfoMoreIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `RecordInfoDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | ### Voice room The full-screen voice conversation room. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ----------------------------------------- | ---------------- | --------- | --------- | | `VoiceRoomBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `VoiceRoomTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `VoiceRoomErrorPulseColor` | `onSurface3` | `#939393` | `#E0E0E0` | | `VoiceRoomCircleButtonBorderColor` | `border1` | `#DEDFE1` | `#6E6D6D` | | `VoiceRoomCircleButtonSelectedBackground` | per-mode literal | `#ECF5FE` | `#3A3A3A` | ### Record selector Record picker list. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------------ | ------------------- | --------- | --------- | | `RecordSelectorTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `RecordSelectorDisabledTextColor` | `onDisabled1` | `#898A8D` | `#C1C1C1` | | `RecordSelectorRadioSelectedColor` | `accent1` | `#0170CB` | `#008AF7` | | `RecordSelectorRadioUnselectedColor` | `surfaceContainer3` | `#D8D8D8` | `#BEBEBE` | | `RecordSelectorDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | ### JSON object viewer Expandable JSON object viewer. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `JsonViewerBackground` | `surfaceContainer1` | `#F3F3F3` | `#2E2E2E` | | `JsonViewerTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `JsonViewerExpandTextColor` | `accent1` | `#0170CB` | `#008AF7` | | `JsonViewerDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | | `JsonViewerFadeOverlayColor` | `surfaceContainer1` | `#F3F3F3` | `#2E2E2E` | ### Email Email component surface. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `EmailBackground` | `surfaceContainer1` | `#F3F3F3` | `#2E2E2E` | ### Stencil / loading skeleton Shimmer placeholder while content loads. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `StencilShimmerColor` | `surfaceContainer3` | `#D8D8D8` | `#BEBEBE` | ### Action sheet Record-actions sheet. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------ | --------- | --------- | | `ActionSheetBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `ActionSheetIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `ActionSheetTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `ActionSheetExternalIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `ActionSheetDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | ### Toxicity Toxicity warning block. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------ | --------- | --------- | | `ToxicityTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `ToxicityIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `ToxicityDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | ### Form field Shared by pre-chat field, secure-form field, text input, and pickers. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | -------------------- | --------- | --------- | | `FormFieldLabelColor` | `onSurface2` | `#222222` | `#E8E8E8` | | `FormFieldErrorColor` | `error1` | `#BA0517` | `#E24857` | | `FormFieldRequiredColor` | `error1` | `#BA0517` | `#E24857` | | `FormFieldBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `FormFieldDisabledBackground` | `disabledContainer1` | `#EBEBEB` | `#2D2D30` | | `FormFieldBorderColor` | `onSurface3` | `#939393` | `#E0E0E0` | | `FormFieldErrorBorderColor` | `error1` | `#BA0517` | `#E24857` | | `FormFieldTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `FormFieldDisabledTextColor` | `onDisabled1` | `#898A8D` | `#C1C1C1` | | `FormFieldPlaceholderColor` | `onSurface3` | `#939393` | `#E0E0E0` | | `FormFieldArrowTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `FormFieldCursorColor` | `accent1` | `#0170CB` | `#008AF7` | | `FormFieldClearIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | ### Checkbox Checkbox and its label. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | -------------------- | --------- | --------- | | `CheckBoxBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `CheckBoxDisabledBackground` | `disabledContainer1` | `#EBEBEB` | `#2D2D30` | | `CheckBoxCheckedColor` | `accent1` | `#0170CB` | `#008AF7` | | `CheckBoxUncheckedColor` | `onSurface3` | `#939393` | `#E0E0E0` | | `CheckBoxCheckmarkColor` | `onAccent1` | `#FFFFFF` | `#FFFFFF` | | `CheckBoxLabelColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `CheckBoxDisabledLabelColor` | `onDisabled1` | `#898A8D` | `#C1C1C1` | | `CheckBoxDisabledFillColor` | `onDisabled1` | `#898A8D` | `#C1C1C1` | ### Pre-chat form Pre-chat form page. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------------- | ------------- | --------- | --------- | | `PreChatFormPageBackground` | `accent3` | `#D6E6FF` | `#3A3A3A` | | `PreChatFormInstructionColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `PreChatFormAvatarBackground` | `accent1` | `#0170CB` | `#008AF7` | | `PreChatFormAvatarIconTint` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `PreChatFormSubmitBackground` | `accent1` | `#0170CB` | `#008AF7` | | `PreChatFormSubmitTextColor` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `PreChatFormSubmitDisabledBackground` | `onDisabled2` | `#DADADA` | `#666666` | | `PreChatFormSubmitDisabledTextColor` | `onDisabled1` | `#898A8D` | `#C1C1C1` | | `PreChatFormRequiredColor` | `error1` | `#BA0517` | `#E24857` | ### Secure form Secure form page. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------------ | ------------- | --------- | --------- | | `SecureFormPageBackground` | `accent3` | `#D6E6FF` | `#3A3A3A` | | `SecureFormTitleColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `SecureFormSubmitBackground` | `accent1` | `#0170CB` | `#008AF7` | | `SecureFormSubmitTextColor` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `SecureFormSubmitDisabledBackground` | `onDisabled2` | `#DADADA` | `#666666` | | `SecureFormSubmitDisabledTextColor` | `onDisabled1` | `#898A8D` | `#C1C1C1` | | `SecureFormReadOnlyRequiredColor` | `onSurface3` | `#939393` | `#E0E0E0` | | `SecureFormSpinnerTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `SecureFormSuccessTitleColor` | `onSurface1` | `#000000` | `#FFFFFF` | ### Secure form link Secure form link chip. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `SecureFormLinkBackground` | `surfaceContainer2` | `#F5F5F5` | `#777777` | | `SecureFormLinkTitleColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `SecureFormLinkIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | ### Generic attachment / file chip Attachment remove button, chip preview, border. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ---------------------------------- | ------------------- | --------- | --------- | | `AttachmentRemoveButtonBackground` | `onSurface3` | `#939393` | `#E0E0E0` | | `AttachmentRemoveButtonTint` | `accent2` | `#F2F2F2` | `#777777` | | `AttachmentChipPreviewBackground` | `surface2` | `#F3F3F3` | `#302D2D` | | `AttachmentBorderColor` | `surfaceContainer3` | `#D8D8D8` | `#BEBEBE` | ### Image / PDF preview placeholder Placeholder shown before a preview loads. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ---------------------------------------- | ------------------- | --------- | --------- | | `AttachmentPreviewPlaceholderBackground` | `surfaceContainer3` | `#D8D8D8` | `#BEBEBE` | | `AttachmentChipMimeTypeColor` | `onSurface1` | `#000000` | `#FFFFFF` | ### Audio attachment Audio attachment player. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | --------------------------------- | ------------------- | --------- | --------- | | `AudioAttachmentBackground` | `surfaceContainer2` | `#F5F5F5` | `#777777` | | `AudioAttachmentTitleColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `AudioAttachmentDurationColor` | `onSurface2` | `#222222` | `#E8E8E8` | | `AudioAttachmentErrorColor` | `error1` | `#BA0517` | `#E24857` | | `AudioAttachmentProgressColor` | `accent1` | `#0170CB` | `#008AF7` | | `AudioAttachmentButtonBackground` | `surfaceContainer3` | `#D8D8D8` | `#BEBEBE` | ### Video attachment Video attachment preview. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | -------------------------------------- | ------------------- | --------- | --------- | | `VideoAttachmentPlaceholderBackground` | `surfaceContainer2` | `#F5F5F5` | `#777777` | | `VideoAttachmentPlayButtonBackground` | `onAccent1` | `#FFFFFF` | `#FFFFFF` | | `VideoAttachmentPlayIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | ### PDF attachment PDF attachment chip. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `AttachmentBackground` | `surfaceContainer2` | `#F5F5F5` | `#777777` | | `AttachmentTitleColor` | `onSurface1` | `#000000` | `#FFFFFF` | ### PDF viewer (full screen) Full-screen PDF viewer page. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------- | --------- | --------- | | `PdfViewerPageBackground` | fixed literal | `#FFFFFF` | `#FFFFFF` | ### Media viewer Image preview / video player chrome. The close-button scrim gets about 45% alpha at the call site. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | -------------------------------- | ------------------- | --------- | --------- | | `MediaViewerBackground` | fixed literal | `#000000` | `#000000` | | `MediaViewerCloseIconTint` | fixed literal | `#FFFFFF` | `#FFFFFF` | | `MediaViewerCloseIconBackground` | fixed literal | `#000000` | `#000000` | | `MediaViewerControlBackground` | `surfaceContainer3` | `#D8D8D8` | `#BEBEBE` | | `MediaViewerControlIconTint` | `onSurface1` | `#000000` | `#FFFFFF` | ### Aura The animated brand aura / avatar glow (brand-seeded). | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ---------------- | --------- | --------- | | `AuraColor1` | fixed literal | `#1589EE` | `#1589EE` | | `AuraColor2` | fixed literal | `#4892E7` | `#4892E7` | | `AuraAvatarBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `AuraAvatarIconTint` | per-mode literal | `#0176D3` | `#008AF7` | ### Markdown text Markdown-rendered agent text. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ---------------- | --------- | --------- | | `MarkdownTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `MarkdownLinkColor` | per-mode literal | `#0170CB` | `#008AF7` | | `MarkdownBlockquoteColor` | `border1` | `#DEDFE1` | `#6E6D6D` | | `MarkdownThematicBreakColor` | `border1` | `#DEDFE1` | `#6E6D6D` | ### Rich text (HTML) HTML-rendered rich text. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `RichTextBackground` | `surfaceContainer1` | `#F3F3F3` | `#2E2E2E` | | `RichTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `RichTextLinkColor` | per-mode literal | `#0170CB` | `#008AF7` | ### Streaming card Streaming card fade and action text. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ----------- | --------- | --------- | | `StreamingCardFadeColor` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `StreamingCardActionTextColor` | `accent1` | `#0170CB` | `#008AF7` | ### Chat status Status line under the chat. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------ | --------- | --------- | | `ChatStatusLineColor` | `border1` | `#DEDFE1` | `#6E6D6D` | | `ChatStatusTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | ### Progress indicator Typing / progress indicator. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------- | ------------ | --------- | --------- | | `ProgressIndicatorTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `ProgressIndicatorDotColor` | `onSurface3` | `#939393` | `#E0E0E0` | | `ProgressIndicatorSparkleColor` | `accent1` | `#0170CB` | `#008AF7` | ### Full-screen states Loading, error, and onboarding full-screen states. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------ | --------- | --------- | | `FullScreenTitleColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `SpinnerColor` | `accent1` | `#0170CB` | `#008AF7` | | `FullScreenBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `FullScreenBodyColor` | `onSurface1` | `#000000` | `#FFFFFF` | ### Refresh button Refresh button on the error screen. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ----------- | --------- | --------- | | `RefreshButtonBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `RefreshButtonBorderColor` | `border1` | `#DEDFE1` | `#6E6D6D` | | `RefreshButtonTextColor` | `accent1` | `#0170CB` | `#008AF7` | | `RefreshButtonIconTint` | `accent1` | `#0170CB` | `#008AF7` | ### Onboarding confirm button Confirm button on the onboarding screen. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ----------- | --------- | --------- | | `OnboardingButtonBackground` | `accent1` | `#0170CB` | `#008AF7` | | `OnboardingButtonTextColor` | `onAccent1` | `#FFFFFF` | `#FFFFFF` | | `OnboardingDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | ### Generic CTA button Generic call-to-action button. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `CtaButtonBackground` | `accent1` | `#0170CB` | `#008AF7` | | `CtaButtonTextColor` | `onAccent1` | `#FFFFFF` | `#FFFFFF` | | `CtaButtonBorderColor` | `surfaceContainer3` | `#D8D8D8` | `#BEBEBE` | ## Notes - Values are `#RRGGBB` and fully opaque. A few tokens (for example the media-viewer scrim) apply transparency where they're used. - `OnAccent1` is white in both modes by design (text and icons on the accent fill). ## Related Documentation - [Theming](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guides/android/agentforce-mobile-sdk-android-branding-theming.md) - [AgentforceThemeManager](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-theme-manager-android.md) - [AgentforceTypography](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-typography-android.md) - [Server-Driven Branding](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/server-driven-branding-android.md) # Color Token Reference This page lists every color token the Agentforce iOS SDK exposes for [theming](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guides/ios/agentforce-mobile-sdk-ios-branding-theming.md), with its default value in both light and dark mode. There are **275 color tokens** in total: **51 generic tokens** and **224 component tokens** across **50 component groups**. Groups and token order match `AgentforceColorPalette`, so this page reads top-to-bottom the same way the components are laid out. ## How tokens resolve The palette has two layers: 1. **Generic tokens** (declared by `SharedUI.Colors`): `surface1`, `accent1`, `onSurface1`, `border1`, and so on. These carry explicit light and dark values. 2. **Component tokens** (declared by `AgentforceColorPalette`): every UI element has its own token — for example `titleBarBackground`, `sendButtonEnabledBackground`, `carouselSurface`. Each one falls back directly to a generic token, with no component-to-component chaining, so changing one component never affects another that happens to share the same color. Each component token resolves its default in one of three ways: - **Alias** — falls back to a generic token (shown in the **Resolves to** column). Its default light and dark values are that generic token's values. - **Fixed literal** — a single color that's identical in light and dark. - **Per-mode literal** — distinct light and dark colors, seeded from the Cosmos brand palette. Override any token — generic or component — through `AgentforceThemeOverrides`, or by subclassing `AgentforceCosmosLightColors` / `AgentforceCosmosDarkColors`. See [Theming](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guides/ios/agentforce-mobile-sdk-ios-branding-theming.md) for usage. **Only aliases cascade.** Overriding a generic token moves every component token that aliases it, but the 16 tokens below hold a literal instead of an alias, so a generic override never reaches them. Set them individually if you need to move them: `richTextLinkColor`, `markdownLinkColor`, `citationExternalLinkDefaultColor`, `attachmentPreviewPlaceholderBackground`, `pdfViewerPageBackground`, `mediaViewerBackground`, `mediaViewerCloseIconTint`, `mediaViewerCloseIconBackground`, `auraAvatarIconTint`, `auraColor1`, `auraColor2`, `inputBarPlaceholderColor`, `launcherPlaceholderColor`, `agentAvatarLiveBackground`, `utteranceBackground`, `voiceRoomCircleButtonSelectedBackground`. Most notably, link colors are in that list — overriding `.accent1` does **not** change the color of links in rich text or markdown. Each token's `rawValue` is identical to its palette property name. ## Generic tokens The design-system base palette. Every component token below ultimately resolves to one of these (unless it's a fixed or per-mode literal). Override these to re-skin the whole UI at once. A caveat on breadth: 21 of these generic tokens are declared by the shared design system but aren't currently read by any Agentforce view, so overriding them has no visible effect today — `borderInverse2`, `borderDisabled1`, `accentContainer2`, `borderAccent1`, `borderAccent2`, `errorContainer2`, `borderError1`, `successContainer2`, `success1`, `disabled1`, `disabledContainer2`, `brandBase50`, `brandBase70`, `brandBase90`, `errorBase50`, `feedbackWarning1`, `feedbackWarningContainer1`, `warning1`, `information1`, `informationContainer1`, and `cloudBlue60`. They're listed for completeness and may become live as more shared components are adopted. | Token (`AgentforceColorToken`) | Light | Dark | | ------------------------------ | --------- | --------- | | `.surface1` | `#FFFFFF` | `#1F1F1F` | | `.surface2` | `#F3F3F3` | `#302D2D` | | `.onSurface1` | `#000000` | `#FFFFFF` | | `.onSurface2` | `#222222` | `#E8E8E8` | | `.onSurface3` | `#939393` | `#E0E0E0` | | `.onSurfaceInverse1` | `#FFFFFF` | `#FFFFFF` | | `.surfaceContainer1` | `#F3F3F3` | `#2E2E2E` | | `.surfaceContainer2` | `#F5F5F5` | `#777777` | | `.surfaceContainer3` | `#D8D8D8` | `#BEBEBE` | | `.surfaceContainerInverse1` | `#032D60` | `#032D60` | | `.border1` | `#DEDFE1` | `#6E6D6D` | | `.border2` | `#DADCE0` | `#5F6368` | | `.borderInverse2` | `#032D60` | `#032D60` | | `.borderDisabled1` | `#C9C9C9` | `#C9C9C9` | | `.accent1` | `#0170CB` | `#008AF7` | | `.accent2` | `#F2F2F2` | `#777777` | | `.accent3` | `#D6E6FF` | `#3A3A3A` | | `.accentContainer1` | `#E9F5FF` | `#0077D9` | | `.accentContainer2` | `#0250D9` | `#0250D9` | | `.onAccent1` | `#FFFFFF` | `#FFFFFF` | | `.borderAccent1` | `#066AFE` | `#066AFE` | | `.borderAccent2` | `#0250D9` | `#0250D9` | | `.error1` | `#BA0517` | `#E24857` | | `.errorContainer1` | `#FCE8E6` | `#FEB8AB` | | `.errorContainer2` | `#FDB6C5` | `#FDB6C5` | | `.onError1` | `#EA4335` | `#9B000F` | | `.borderError1` | `#BA0517` | `#9B000F` | | `.successContainer1` | `#2E844A` | `#2E844A` | | `.successContainer2` | `#04E1CB` | `#04E1CB` | | `.success1` | `#056764` | `#056764` | | `.onSuccess1` | `#FFFFFF` | `#FFFFFF` | | `.borderSuccess1` | `#2E844A` | `#2E844A` | | `.disabled1` | `#C9C9C9` | `#C9C9C9` | | `.disabledContainer1` | `#EBEBEB` | `#2D2D30` | | `.disabledContainer2` | `#E8EAED` | `#484848` | | `.onDisabled1` | `#898A8D` | `#C1C1C1` | | `.onDisabled2` | `#DADADA` | `#666666` | | `.brandBase50` | `#066AFE` | `#066AFE` | | `.brandBase70` | `#7CB1FE` | `#7CB1FE` | | `.brandBase90` | `#E3F2FD` | `#2A3441` | | `.errorBase50` | `#E3066A` | `#E3066A` | | `.feedbackWarning1` | `#8C4B02` | `#8C4B02` | | `.feedbackWarningContainer1` | `#F9E3B6` | `#F9E3B6` | | `.warning1` | `#8C4B02` | `#8C4B02` | | `.warningContainer1` | `#F9E3B6` | `#F9E3B6` | | `.info1` | `#0B5CAB` | `#0B5CAB` | | `.infoContainer1` | `#D8E6FE` | `#D8E6FE` | | `.information1` | `#0B5CAB` | `#0B5CAB` | | `.informationContainer1` | `#D8E6FE` | `#D8E6FE` | | `.onWarning1` | `#8C4B02` | `#8C4B02` | | `.cloudBlue60` | `#0D9DDA` | `#0D9DDA` | ## Component tokens Every UI element has its own token, grouped below by component. ### Chat scaffold The root chat surface. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ----------- | --------- | --------- | | `.chatBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | ### Title bar / navigation The conversation header (title, icons, divider). | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------ | --------- | --------- | | `.titleBarBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.titleBarTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.titleBarIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `.titleBarDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | ### Input bar The message composer row. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | --------------------------------- | ---------------- | --------- | --------- | | `.inputBarBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.inputBarListeningBackground` | `accent3` | `#D6E6FF` | `#3A3A3A` | | `.inputBarFieldBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.inputBarFieldBorderColor` | `onSurface3` | `#939393` | `#E0E0E0` | | `.inputBarTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.inputBarPlaceholderColor` | per-mode literal | `#757575` | `#D2D2D2` | | `.inputBarIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `.inputBarTopDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | | `.inputBarCursorColor` | `accent1` | `#0170CB` | `#008AF7` | | `.inputBarAttachmentDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | ### Send button The send-message button. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------- | ------------- | --------- | --------- | | `.sendButtonEnabledBackground` | `accent1` | `#0170CB` | `#008AF7` | | `.sendButtonDisabledBackground` | `onDisabled1` | `#898A8D` | `#C1C1C1` | | `.sendButtonIconTint` | `onAccent1` | `#FFFFFF` | `#FFFFFF` | ### Voice / stop-listening button The voice-entry button in the input bar. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------ | --------- | --------- | | `.voiceButtonBackground` | `onSurface1` | `#000000` | `#FFFFFF` | | `.voiceButtonBorder` | `onSurface1` | `#000000` | `#FFFFFF` | | `.voiceButtonAccentColor` | `accent1` | `#0170CB` | `#008AF7` | ### Agent avatar The agent avatar in the chat feed. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ---------------- | --------- | --------- | | `.agentAvatarBackground` | `accent3` | `#D6E6FF` | `#3A3A3A` | | `.agentAvatarIconTint` | `accent1` | `#0170CB` | `#008AF7` | | `.agentAvatarLiveBackground` | per-mode literal | `#05628A` | `#FFFFFF` | | `.agentAvatarLiveIconTint` | `accent3` | `#D6E6FF` | `#3A3A3A` | ### Agent message Agent name and message text. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------ | --------- | --------- | | `.agentMessageNameColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.agentMessageTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | ### User message bubble The end user's message bubble. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------ | --------- | --------- | | `.userMessageBubbleBackground` | `accentContainer1` | `#E9F5FF` | `#0077D9` | | `.userMessageBubbleTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.userMessageStatusColor` | `onSurface2` | `#222222` | `#E8E8E8` | | `.userMessageErrorColor` | `error1` | `#BA0517` | `#E24857` | ### Chat response / reply button Suggested reply and chat-response buttons. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | --------------------------------------- | ------------- | --------- | --------- | | `.chatResponseButtonBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.chatResponseButtonTextColor` | `accent1` | `#0170CB` | `#008AF7` | | `.chatResponseButtonDisabledBackground` | `onDisabled2` | `#DADADA` | `#666666` | | `.chatResponseButtonDisabledTextColor` | `onDisabled1` | `#898A8D` | `#C1C1C1` | | `.chatResponseButtonPrimaryBackground` | `accent1` | `#0170CB` | `#008AF7` | | `.chatResponseButtonPrimaryTextColor` | `onAccent1` | `#FFFFFF` | `#FFFFFF` | ### Message action buttons Thumbs up / down / copy row under a message. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | -------------------------------- | ------------ | --------- | --------- | | `.messageActionIconActiveTint` | `accent1` | `#0170CB` | `#008AF7` | | `.messageActionIconInactiveTint` | `onSurface3` | `#939393` | `#E0E0E0` | ### Feedback modal The "why wasn't this helpful?" feedback sheet. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ----------------------------------- | -------------------- | --------- | --------- | | `.feedbackBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.feedbackTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.feedbackBorderColor` | `border1` | `#DEDFE1` | `#6E6D6D` | | `.feedbackButtonBackground` | `accent1` | `#0170CB` | `#008AF7` | | `.feedbackButtonDisabledBackground` | `disabledContainer1` | `#EBEBEB` | `#2D2D30` | | `.feedbackButtonTextColor` | `onAccent1` | `#FFFFFF` | `#FFFFFF` | | `.feedbackButtonDisabledTextColor` | `onDisabled1` | `#898A8D` | `#C1C1C1` | ### Toast The four toast status styles. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `.toastInfoBackground` | `infoContainer1` | `#D8E6FE` | `#D8E6FE` | | `.toastInfoForeground` | `info1` | `#0B5CAB` | `#0B5CAB` | | `.toastSuccessBackground` | `successContainer1` | `#2E844A` | `#2E844A` | | `.toastSuccessForeground` | `onSuccess1` | `#FFFFFF` | `#FFFFFF` | | `.toastWarningBackground` | `warningContainer1` | `#F9E3B6` | `#F9E3B6` | | `.toastWarningForeground` | `onWarning1` | `#8C4B02` | `#8C4B02` | | `.toastErrorBackground` | `errorContainer1` | `#FCE8E6` | `#FEB8AB` | | `.toastErrorForeground` | `onError1` | `#EA4335` | `#9B000F` | ### Modal sheet More menu, multi-modal sheet, action list, agent selector. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | --------------------------------- | ------------ | --------- | --------- | | `.modalSheetBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.modalSheetTitleColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.modalSheetItemTextColor` | `onSurface2` | `#222222` | `#E8E8E8` | | `.modalSheetItemIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `.modalSheetDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | | `.modalSheetDoneButtonBackground` | `accent1` | `#0170CB` | `#008AF7` | | `.modalSheetDoneButtonTextColor` | `onAccent1` | `#FFFFFF` | `#FFFFFF` | ### Inline chat error Error shown inline inside an agent response. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ----------------- | --------- | --------- | | `.messageErrorBackground` | `errorContainer1` | `#FCE8E6` | `#FEB8AB` | | `.messageErrorTextColor` | `error1` | `#BA0517` | `#E24857` | ### Launcher The floating launcher entry point. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ---------------- | --------- | --------- | | `.launcherBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.launcherInputBorderColor` | `onSurface3` | `#939393` | `#E0E0E0` | | `.launcherIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `.launcherTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.launcherUnreadDotColor` | `accent1` | `#0170CB` | `#008AF7` | | `.launcherFlashBackground` | `accent3` | `#D6E6FF` | `#3A3A3A` | | `.launcherIconTileTint` | `accent1` | `#0170CB` | `#008AF7` | | `.launcherPlaceholderColor` | per-mode literal | `#757575` | `#D2D2D2` | ### Recommended utterance Suggested-utterance chips and their list. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ---------------- | --------- | --------- | | `.utteranceBackground` | per-mode literal | `#ECF5FE` | `#3A3A3A` | | `.utteranceTextColor` | `accent1` | `#0170CB` | `#008AF7` | | `.utteranceIconTint` | `accent1` | `#0170CB` | `#008AF7` | | `.utteranceListLabelColor` | `onSurface2` | `#222222` | `#E8E8E8` | | `.utteranceListBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | ### Carousel The horizontal card carousel. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------ | --------- | --------- | | `.carouselSurface` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.carouselItemBorderColor` | `accent1` | `#0170CB` | `#008AF7` | | `.carouselTitleColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.carouselDotSelectedColor` | `accent1` | `#0170CB` | `#008AF7` | | `.carouselDotUnselectedColor` | `onSurface3` | `#939393` | `#E0E0E0` | | `.carouselFadeOverlayColor` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.carouselPlaceholderTint` | `onSurface3` | `#939393` | `#E0E0E0` | ### Source / citation Citation chips, list, and external link. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ----------------------------------- | ------------------- | --------- | --------- | | `.citationBackground` | `surfaceContainer1` | `#F3F3F3` | `#2E2E2E` | | `.citationTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.citationIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `.citationListBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.citationDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | | `.citationExternalLinkDefaultColor` | fixed literal | `#4892E7` | `#4892E7` | ### Rich link Rich link preview card. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `.richLinkBackground` | `surfaceContainer2` | `#F5F5F5` | `#777777` | | `.richLinkImageBackground` | `surfaceContainer2` | `#F5F5F5` | `#777777` | | `.richLinkPlaceholderTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `.richLinkTitleColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.richLinkUrlColor` | `onSurface2` | `#222222` | `#E8E8E8` | ### Web link Inline web link chip. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `.webLinkBackground` | `surfaceContainer2` | `#F5F5F5` | `#777777` | | `.webLinkTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.webLinkFaviconTint` | `onSurface3` | `#939393` | `#E0E0E0` | ### Record info Record info card. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `.recordInfoBackground` | `surfaceContainer1` | `#F3F3F3` | `#2E2E2E` | | `.recordInfoTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.recordInfoLabelColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.recordInfoMoreIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `.recordInfoDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | ### Voice room The full-screen voice conversation room, including its circle buttons (mute, stop, closed captions). | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------------------ | ---------------- | --------- | --------- | | `.voiceRoomBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.voiceRoomTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.voiceRoomErrorPulseColor` | `onSurface3` | `#939393` | `#E0E0E0` | | `.voiceRoomCircleButtonBorderColor` | `border1` | `#DEDFE1` | `#6E6D6D` | | `.voiceRoomCircleButtonSelectedBackground` | per-mode literal | `#ECF5FE` | `#3A3A3A` | ### Record selector Record picker list. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------------- | ------------------- | --------- | --------- | | `.recordSelectorTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.recordSelectorDisabledTextColor` | `onDisabled1` | `#898A8D` | `#C1C1C1` | | `.recordSelectorRadioSelectedColor` | `accent1` | `#0170CB` | `#008AF7` | | `.recordSelectorRadioUnselectedColor` | `surfaceContainer3` | `#D8D8D8` | `#BEBEBE` | | `.recordSelectorDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | ### JSON object viewer Expandable JSON object viewer. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `.jsonViewerBackground` | `surfaceContainer1` | `#F3F3F3` | `#2E2E2E` | | `.jsonViewerTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.jsonViewerExpandTextColor` | `accent1` | `#0170CB` | `#008AF7` | | `.jsonViewerDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | | `.jsonViewerFadeOverlayColor` | `surfaceContainer1` | `#F3F3F3` | `#2E2E2E` | ### Email Email component surface. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `.emailBackground` | `surfaceContainer1` | `#F3F3F3` | `#2E2E2E` | ### Stencil / loading skeleton Shimmer placeholder while content loads. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `.stencilShimmerColor` | `surfaceContainer3` | `#D8D8D8` | `#BEBEBE` | ### Action sheet Record-actions sheet. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------ | --------- | --------- | | `.actionSheetBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.actionSheetIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `.actionSheetTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.actionSheetExternalIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `.actionSheetDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | ### Toxicity Toxicity warning block. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------ | --------- | --------- | | `.toxicityTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.toxicityIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `.toxicityDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | ### Form field Shared by pre-chat field, secure-form field, text input, and pickers. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | -------------------- | --------- | --------- | | `.formFieldLabelColor` | `onSurface2` | `#222222` | `#E8E8E8` | | `.formFieldErrorColor` | `error1` | `#BA0517` | `#E24857` | | `.formFieldRequiredColor` | `error1` | `#BA0517` | `#E24857` | | `.formFieldBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.formFieldDisabledBackground` | `disabledContainer1` | `#EBEBEB` | `#2D2D30` | | `.formFieldBorderColor` | `onSurface3` | `#939393` | `#E0E0E0` | | `.formFieldErrorBorderColor` | `error1` | `#BA0517` | `#E24857` | | `.formFieldTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.formFieldDisabledTextColor` | `onDisabled1` | `#898A8D` | `#C1C1C1` | | `.formFieldPlaceholderColor` | `onSurface3` | `#939393` | `#E0E0E0` | | `.formFieldArrowTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `.formFieldCursorColor` | `accent1` | `#0170CB` | `#008AF7` | | `.formFieldClearIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | ### Checkbox Checkbox and its label. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | -------------------- | --------- | --------- | | `.checkBoxBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.checkBoxDisabledBackground` | `disabledContainer1` | `#EBEBEB` | `#2D2D30` | | `.checkBoxCheckedColor` | `accent1` | `#0170CB` | `#008AF7` | | `.checkBoxUncheckedColor` | `onSurface3` | `#939393` | `#E0E0E0` | | `.checkBoxCheckmarkColor` | `onAccent1` | `#FFFFFF` | `#FFFFFF` | | `.checkBoxLabelColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.checkBoxDisabledLabelColor` | `onDisabled1` | `#898A8D` | `#C1C1C1` | | `.checkBoxDisabledFillColor` | `onDisabled1` | `#898A8D` | `#C1C1C1` | ### Pre-chat form Pre-chat form page. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | -------------------------------------- | ------------- | --------- | --------- | | `.preChatFormPageBackground` | `accent3` | `#D6E6FF` | `#3A3A3A` | | `.preChatFormInstructionColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.preChatFormAvatarBackground` | `accent1` | `#0170CB` | `#008AF7` | | `.preChatFormAvatarIconTint` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.preChatFormSubmitBackground` | `accent1` | `#0170CB` | `#008AF7` | | `.preChatFormSubmitTextColor` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.preChatFormSubmitDisabledBackground` | `onDisabled2` | `#DADADA` | `#666666` | | `.preChatFormSubmitDisabledTextColor` | `onDisabled1` | `#898A8D` | `#C1C1C1` | | `.preChatFormRequiredColor` | `error1` | `#BA0517` | `#E24857` | ### Secure form Secure form page. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------------- | ------------- | --------- | --------- | | `.secureFormPageBackground` | `accent3` | `#D6E6FF` | `#3A3A3A` | | `.secureFormTitleColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.secureFormSubmitBackground` | `accent1` | `#0170CB` | `#008AF7` | | `.secureFormSubmitTextColor` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.secureFormSubmitDisabledBackground` | `onDisabled2` | `#DADADA` | `#666666` | | `.secureFormSubmitDisabledTextColor` | `onDisabled1` | `#898A8D` | `#C1C1C1` | | `.secureFormReadOnlyRequiredColor` | `onSurface3` | `#939393` | `#E0E0E0` | | `.secureFormSpinnerTint` | `onSurface3` | `#939393` | `#E0E0E0` | | `.secureFormSuccessTitleColor` | `onSurface1` | `#000000` | `#FFFFFF` | ### Secure form link Secure form link chip. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `.secureFormLinkBackground` | `surfaceContainer2` | `#F5F5F5` | `#777777` | | `.secureFormLinkTitleColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.secureFormLinkIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | ### Generic attachment / file chip Attachment remove button, chip preview, border. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ----------------------------------- | ------------------- | --------- | --------- | | `.attachmentRemoveButtonBackground` | `onSurface3` | `#939393` | `#E0E0E0` | | `.attachmentRemoveButtonTint` | `accent2` | `#F2F2F2` | `#777777` | | `.attachmentChipPreviewBackground` | `surface2` | `#F3F3F3` | `#302D2D` | | `.attachmentBorderColor` | `surfaceContainer3` | `#D8D8D8` | `#BEBEBE` | ### Image / PDF preview placeholder Placeholder shown before a preview loads. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ----------------------------------------- | ------------- | --------- | --------- | | `.attachmentPreviewPlaceholderBackground` | fixed literal | `#E5E5E5` | `#E5E5E5` | | `.attachmentChipMimeTypeColor` | `onSurface1` | `#000000` | `#FFFFFF` | ### Audio attachment Audio attachment player. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ---------------------------------- | ------------------- | --------- | --------- | | `.audioAttachmentBackground` | `surfaceContainer2` | `#F5F5F5` | `#777777` | | `.audioAttachmentTitleColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.audioAttachmentDurationColor` | `onSurface2` | `#222222` | `#E8E8E8` | | `.audioAttachmentErrorColor` | `error1` | `#BA0517` | `#E24857` | | `.audioAttachmentProgressColor` | `accent1` | `#0170CB` | `#008AF7` | | `.audioAttachmentButtonBackground` | `surfaceContainer3` | `#D8D8D8` | `#BEBEBE` | ### Video attachment Video attachment preview. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | --------------------------------------- | ------------------- | --------- | --------- | | `.videoAttachmentPlaceholderBackground` | `surfaceContainer2` | `#F5F5F5` | `#777777` | | `.videoAttachmentPlayButtonBackground` | `onAccent1` | `#FFFFFF` | `#FFFFFF` | | `.videoAttachmentPlayIconTint` | `onSurface3` | `#939393` | `#E0E0E0` | ### PDF attachment PDF attachment chip. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `.attachmentBackground` | `surfaceContainer2` | `#F5F5F5` | `#777777` | | `.attachmentTitleColor` | `onSurface1` | `#000000` | `#FFFFFF` | ### PDF viewer (full screen) Full-screen PDF viewer page. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------- | --------- | --------- | | `.pdfViewerPageBackground` | fixed literal | `#FFFFFF` | `#FFFFFF` | ### Media viewer Image preview and video player chrome. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | --------------------------------- | ------------------- | ---------------------- | ---------------------- | | `.mediaViewerBackground` | fixed literal | `#000000` | `#000000` | | `.mediaViewerCloseIconTint` | fixed literal | `#FFFFFF` | `#FFFFFF` | | `.mediaViewerCloseIconBackground` | fixed literal | `#000000` at 45% alpha | `#000000` at 45% alpha | | `.mediaViewerControlBackground` | `surfaceContainer3` | `#D8D8D8` | `#BEBEBE` | | `.mediaViewerControlIconTint` | `onSurface1` | `#000000` | `#FFFFFF` | ### Aura The animated brand aura / avatar glow. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ---------------- | --------- | --------- | | `.auraColor1` | fixed literal | `#1589EE` | `#1589EE` | | `.auraColor2` | fixed literal | `#4892E7` | `#4892E7` | | `.auraAvatarBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.auraAvatarIconTint` | per-mode literal | `#0176D3` | `#008AF7` | ### Markdown text Markdown-rendered agent text. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ---------------- | --------- | --------- | | `.markdownTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.markdownLinkColor` | per-mode literal | `#0170CB` | `#008AF7` | | `.markdownBlockquoteColor` | `border1` | `#DEDFE1` | `#6E6D6D` | | `.markdownThematicBreakColor` | `border1` | `#DEDFE1` | `#6E6D6D` | ### Rich text (HTML) HTML-rendered rich text. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `.richTextBackground` | `surfaceContainer1` | `#F3F3F3` | `#2E2E2E` | | `.richTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.richTextLinkColor` | per-mode literal | `#0170CB` | `#008AF7` | ### Streaming card Streaming card fade and action text. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------- | ----------- | --------- | --------- | | `.streamingCardFadeColor` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.streamingCardActionTextColor` | `accent1` | `#0170CB` | `#008AF7` | ### Chat status Status line under the chat. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------ | --------- | --------- | | `.chatStatusLineColor` | `border1` | `#DEDFE1` | `#6E6D6D` | | `.chatStatusTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | ### Progress indicator Typing / progress indicator. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | -------------------------------- | ------------ | --------- | --------- | | `.progressIndicatorTextColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.progressIndicatorDotColor` | `onSurface3` | `#939393` | `#E0E0E0` | | `.progressIndicatorSparkleColor` | `accent1` | `#0170CB` | `#008AF7` | ### Full-screen states Loading, error, and onboarding full-screen states. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------ | --------- | --------- | | `.fullScreenTitleColor` | `onSurface1` | `#000000` | `#FFFFFF` | | `.spinnerColor` | `accent1` | `#0170CB` | `#008AF7` | | `.fullScreenBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.fullScreenBodyColor` | `onSurface1` | `#000000` | `#FFFFFF` | ### Refresh button Refresh button on the error screen. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ----------- | --------- | --------- | | `.refreshButtonBackground` | `surface1` | `#FFFFFF` | `#1F1F1F` | | `.refreshButtonBorderColor` | `border1` | `#DEDFE1` | `#6E6D6D` | | `.refreshButtonTextColor` | `accent1` | `#0170CB` | `#008AF7` | | `.refreshButtonIconTint` | `accent1` | `#0170CB` | `#008AF7` | ### Onboarding confirm button Confirm button on the onboarding screen. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ----------- | --------- | --------- | | `.onboardingButtonBackground` | `accent1` | `#0170CB` | `#008AF7` | | `.onboardingButtonTextColor` | `onAccent1` | `#FFFFFF` | `#FFFFFF` | | `.onboardingDividerColor` | `border1` | `#DEDFE1` | `#6E6D6D` | ### Generic CTA button Generic call-to-action button. | Token (`AgentforceColorToken`) | Resolves to | Light | Dark | | ------------------------------ | ------------------- | --------- | --------- | | `.ctaButtonBackground` | `accent1` | `#0170CB` | `#008AF7` | | `.ctaButtonTextColor` | `onAccent1` | `#FFFFFF` | `#FFFFFF` | | `.ctaButtonBorderColor` | `surfaceContainer3` | `#D8D8D8` | `#BEBEBE` | ## Notes - Values are `#RRGGBB` and fully opaque unless noted. `mediaViewerCloseIconBackground` is the one token that carries alpha in its default. - `onAccent1` is white in both modes by design (text and icons on the accent fill). - `onSurfaceInverse1`, `surfaceContainerInverse1`, `borderInverse2`, `accentContainer2`, `borderAccent1`, `borderAccent2`, `disabled1`, `borderDisabled1`, `brandBase50`, `brandBase70`, `errorBase50`, `success1`, `successContainer1`, `successContainer2`, `borderSuccess1`, `onSuccess1`, `errorContainer2`, `feedbackWarning1`, `feedbackWarningContainer1`, `warning1`, `warningContainer1`, `onWarning1`, `info1`, `infoContainer1`, `information1`, `informationContainer1`, and `cloudBlue60` are mode-independent in the Cosmos defaults — they carry the same value in light and dark. ## iOS vs. Android differences The two SDKs share a model, not an API. The concepts line up almost exactly — same three-way theming choice, same slot vocabularies — but the host-facing code differs enough that theming can't be written once and translated mechanically, and the out-of-the-box colors aren't identical. **What matches:** the `AgentforceTheming` three-way choice (`.default` / `.overrides` / `.customManager`) and its `setTheming` entry point; 23 icon slots and 45 display-name slots with identical names on both platforms; the same 23 typography styles at the same sizes; and all 224 component color tokens, name for name, with the same fallback wiring. **What differs:** | Area | iOS | Android | | ---------------------------------------- | -------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | | Color token count | 275 (51 generic + 224 component) | 271 (47 generic + 224 component) | | Generic tokens not on the other platform | `borderInverse2`, `brandBase70`, `feedbackWarning1`, `feedbackWarningContainer1` | none | | Reusable palettes | Subclass `AgentforceCosmosLightColors` / `AgentforceCosmosDarkColors` | `withOverrides(...)` on a default palette — no iOS equivalent | | Default manager | `open` class you may subclass | Factory functions (`createDefaultAgentforceThemeManager`, `createCustomAgentforceThemeManager`) | | Reading the theme | Hold the manager instance you passed in (`@Observable`) | Compose `CompositionLocal` (`LocalAgentforceTheme`) | | Theme mode | Set on the theme manager | Carried in the overrides bag | Of the 47 generic tokens both platforms share, 23 ship different default values, because iOS resolves the semantic families through Salesforce Cosmos ramps while Android uses Material-style ramps — and iOS keeps most of them mode-independent where Android ships a distinct dark value. If cross-platform consistency matters, set the status and semantic tokens (success, warning, info, inverse-surface) explicitly on both platforms rather than relying on defaults. ## Related Documentation - [Theming](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guides/ios/agentforce-mobile-sdk-ios-branding-theming.md) - [AgentforceThemeManager](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-theme-manager-ios.md) - [AgentforceDefaultThemeManager](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-default-theme-manager-ios.md) # Configuration Reference - React Native Reference documentation for configuration types in the Agentforce Mobile SDK for React Native. ## AgentConfig The configuration passed to `configure()` is a discriminated union type: ```tsx type AgentConfig = ServiceAgentConfig | EmployeeAgentConfig; ``` ## ServiceAgentConfig Configuration for Service Agent mode (anonymous/guest access). ```tsx interface ServiceAgentConfig { type: "service"; serviceApiURL: string; organizationId: string; esDeveloperName: string; featureFlags?: FeatureFlags; } ``` ### Fields | Field | Type | Required | Description | | ----------------- | -------------- | -------- | -------------------------------------------------------------------------------------------------- | | `type` | `'service'` | Yes | Must be `'service'` | | `serviceApiURL` | `string` | Yes | The Service API URL for your deployment. Found in Setup > Embedded Service Deployments > Settings. | | `organizationId` | `string` | Yes | Your Salesforce Organization ID. Can be 15 or 18 characters. | | `esDeveloperName` | `string` | Yes | The developer name of your Embedded Service deployment. | | `featureFlags` | `FeatureFlags` | No | Optional feature flags. | ## EmployeeAgentConfig Configuration for Employee Agent mode (authenticated access). ```tsx interface EmployeeAgentConfig { type: "employee"; instanceUrl: string; organizationId: string; userId: string; agentId?: string; agentLabel?: string; accessToken?: string; featureFlags?: FeatureFlags; } ``` ### Fields | Field | Type | Required | Description | | ---------------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------ | | `type` | `'employee'` | Yes | Must be `'employee'` | | `instanceUrl` | `string` | Yes | Your Salesforce instance URL (for example, `https://myorg.my.salesforce.com`). | | `organizationId` | `string` | Yes | Salesforce Organization ID. | | `userId` | `string` | Yes | The Salesforce User ID of the authenticated user. | | `agentId` | `string` | No | The Agentforce Agent ID. If omitted and `enableMultiAgent` is true, the SDK picks the first available agent. | | `agentLabel` | `string` | No | A display label shown in the conversation UI title bar (Android). | | `accessToken` | `string` | No | OAuth access token. Can be provided directly or obtained via Mobile SDK auth. | | `featureFlags` | `FeatureFlags` | No | Optional feature flags. | ## FeatureFlags Feature flags control optional SDK capabilities. ```tsx interface FeatureFlags { enableMultiAgent: boolean; // default: true enableMultiModalInput: boolean; // default: false enablePDFUpload: boolean; // default: false enableVoice: boolean; // default: false enableCustomViewProvider: boolean; // default: false } ``` ### Flag Details | Flag | Default | Description | | -------------------------- | ------- | -------------------------------------------------------------------------------------------- | | `enableMultiAgent` | `true` | When true and no `agentId` is specified, the SDK bootstraps and picks from available agents. | | `enableMultiModalInput` | `false` | Enables camera and image attachment capabilities. Requires camera/photo permissions. | | `enablePDFUpload` | `false` | Enables PDF file upload in the conversation. | | `enableVoice` | `false` | Enables voice input (microphone). Requires microphone permission. | | `enableCustomViewProvider` | `false` | Enables the custom view provider system. | ## ConfigurationResult Returned by `configure()` from the native layer: ```tsx interface ConfigurationResult { success: boolean; // Whether configuration succeeded mode: "service" | "employee"; // The mode that was configured description?: string; // Optional description } ``` ## ConfigurationInfo Returned by `getConfigurationInfo()`: ```tsx interface ConfigurationInfo { configured: boolean; // Whether the SDK is configured mode: "service" | "employee" | null; // Current mode, null if not configured description?: string; // Description of the configuration } ``` ## LegacyServiceAgentConfig (Deprecated) For backward compatibility, the bridge accepts the legacy format without a `type` field: ```tsx interface LegacyServiceAgentConfig { serviceApiURL: string; organizationId: string; esDeveloperName: string; } ``` **note:** This format is deprecated. Use `ServiceAgentConfig` with `type: 'service'` instead. ## Type Guards The package exports type guard functions: ```tsx import { isServiceAgentConfig, isEmployeeAgentConfig, isLegacyConfig, } from "@salesforce/react-native-agentforce"; // Returns true if config.type === 'service' isServiceAgentConfig(config); // Returns true if config.type === 'employee' isEmployeeAgentConfig(config); // Returns true if config has no 'type' field isLegacyConfig(config); ``` ## See Also - [Configure the SDK Guide](/docs/ai/agentforce-mobile-sdk/guide/react-native/agentforce-mobile-sdk-react-native-integration) - [Authentication Reference](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/authentication-overview-react-native.md) # Configure the Agentforce SDK for React Native Learn how to configure the Agentforce Mobile SDK for your React Native application. The SDK supports two modes: Service Agent for anonymous customer support, and Employee Agent for authenticated internal use. ## Overview The `configure()` method accepts a configuration object with a `type` field that determines the SDK's operating mode: ```tsx import { AgentforceService } from "@salesforce/react-native-agentforce"; await AgentforceService.configure({ type: "service", // or 'employee' // ... mode-specific fields }); ``` Both modes share `organizationId` and optional `featureFlags`. Other fields are specific to each mode. ## Service Agent Configuration Service Agent mode is for anonymous/guest access, typically for customer-facing support scenarios. No OAuth authentication is required. ### Configuration Fields | Field | Type | Required | Description | | ----------------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `type` | `'service'` | Yes | Must be `'service'` | | `serviceApiURL` | `string` | Yes | The Service API URL for your deployment. Found in Setup > Embedded Service Deployments > Settings. Must be a valid URL (for example, `https://your-site.salesforce.com`). | | `organizationId` | `string` | Yes | Your Salesforce Organization ID. Found in Setup > Company Information. Can be 15 or 18 characters. | | `esDeveloperName` | `string` | Yes | The developer name of your Embedded Service deployment. Found in Setup > Embedded Service Deployments. | | `featureFlags` | `FeatureFlags` | No | Optional feature flags. If omitted, persisted flags (or defaults) are used. | ### Example ```tsx await AgentforceService.configure({ type: "service", serviceApiURL: "https://mycompany-support.my.salesforce-scrt.com", organizationId: "00Dxx0000001234EAA", esDeveloperName: "My_Service_Agent", }); ``` ## Employee Agent Configuration Employee Agent mode is for authenticated, internal-use scenarios. Users must be authenticated with a valid Salesforce OAuth token. ### Configuration Fields | Field | Type | Required | Description | | ---------------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------ | | `type` | `'employee'` | Yes | Must be `'employee'` | | `instanceUrl` | `string` | Yes | Your Salesforce instance URL (for example, `https://myorg.my.salesforce.com`). | | `organizationId` | `string` | Yes | Salesforce Organization ID. | | `userId` | `string` | Yes | The Salesforce User ID of the authenticated user (for example, `005xx0000001234`). | | `agentId` | `string` | No | The Agentforce Agent ID. If omitted and `enableMultiAgent` is true, the SDK picks the first available agent. | | `agentLabel` | `string` | No | A display label shown in the conversation UI title bar (Android). | | `accessToken` | `string` | No | OAuth access token. Can be provided directly or obtained via Mobile SDK auth. | | `featureFlags` | `FeatureFlags` | No | Optional feature flags. | ### Example: Direct Token ```tsx await AgentforceService.configure({ type: "employee", instanceUrl: "https://myorg.my.salesforce.com", organizationId: "00Dxx0000001234EAA", userId: "005xx0000001234AAA", agentId: "0Xxxx0000001234AAA", accessToken: "your_oauth_access_token", }); ``` ### Example: With Mobile SDK Auth When using the Mobile SDK for authentication, obtain credentials first and then pass them to `configure()`: ```tsx import { AgentforceService, loginForEmployeeAgent } from "@salesforce/react-native-agentforce"; // Login via Mobile SDK const creds = await loginForEmployeeAgent(); // Configure with obtained credentials await AgentforceService.configure({ type: "employee", instanceUrl: creds.instanceUrl, organizationId: creds.organizationId, userId: creds.userId, agentId: "0Xxxx0000001234AAA", accessToken: creds.accessToken, }); ``` See [Employee Agent Authentication](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-react-native-employee-auth.md) for details on the Mobile SDK auth integration. ### agentId Behavior The `agentId` field determines which agent the conversation uses: - **If `agentId` is provided**, the conversation starts with that specific agent. - **If `agentId` is omitted and `enableMultiAgent` is `true`** (the default), the SDK bootstraps and picks the first available agent. - **If `agentId` is omitted and `enableMultiAgent` is `false`**, the conversation will likely fail. A warning is logged on both platforms. You can read and write the `agentId` independently of configuration: ```tsx // Read stored agent ID const storedId = await AgentforceService.getEmployeeAgentId(); // Set a new agent ID await AgentforceService.setEmployeeAgentId("0Xxxx0000005678AAA"); ``` **warning:** Platform Difference On **iOS**, calling `setEmployeeAgentId()` with a different agent ID triggers an immediate conversation close and client cleanup. The new agent ID takes effect right away. On **Android**, the method only persists the value. The change takes effect on the next `configure()` or `launchConversation()` call. ## Feature Flags Feature flags control optional SDK capabilities. They can be provided inline with the config or set independently. ```tsx interface FeatureFlags { enableMultiAgent: boolean; // default: true enableMultiModalInput: boolean; // default: false enablePDFUpload: boolean; // default: false enableVoice: boolean; // default: false enableCustomViewProvider: boolean; // default: false } ``` ### Flag Details | Flag | Default | Description | | -------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enableMultiAgent` | `true` | When true and no `agentId` is specified, the SDK bootstraps and picks from available agents. When false, an `agentId` must be provided. | | `enableMultiModalInput` | `false` | Enables camera and image attachment capabilities in the conversation UI. Requires camera/photo permissions. | | `enablePDFUpload` | `false` | Enables PDF file upload in the conversation. | | `enableVoice` | `false` | Enables voice input (microphone) in the conversation UI. Requires microphone permission. | | `enableCustomViewProvider` | `false` | Enables the custom view provider system. When true and a `ViewProviderDelegate` is registered, the SDK delegates rendering of matched component types to your React Native components. | ### Setting Feature Flags **Inline with configure():** ```tsx await AgentforceService.configure({ type: "service", serviceApiURL: url, organizationId: orgId, esDeveloperName: devName, featureFlags: { enableMultiAgent: true, enableMultiModalInput: true, enablePDFUpload: false, enableVoice: false, enableCustomViewProvider: false, }, }); ``` **Independently (persisted):** ```tsx // Save flags -- they take effect the next time configure() is called await AgentforceService.setFeatureFlags({ enableMultiAgent: true, enableMultiModalInput: true, enablePDFUpload: true, enableVoice: false, enableCustomViewProvider: false, }); // Read current flags const flags = await AgentforceService.getFeatureFlags(); console.log(flags.enableMultiModalInput); // true ``` **note:** Changing feature flags via `setFeatureFlags()` does not take effect immediately. You must call `configure()` again (or restart the app) for changes to apply. ### Flag Resolution Order When `configure()` is called, feature flags are resolved in this order: 1. **If `featureFlags` is provided** in the `configure()` call, those values are used. 2. **If `featureFlags` is omitted**, the bridge reads persisted flags from native storage. 3. **If no persisted flags exist**, hard-coded defaults are used (`enableMultiAgent: true`, all others `false`). ## Configuration Lifecycle A typical configuration lifecycle: 1. Set delegates (logger, navigation, view provider) - optional, but do before `configure()` 2. Set hidden prechat fields - optional, Service Agent only, before launch 3. Call `configure()` - required 4. Check `isConfigured()` - optional verification 5. Call `launchConversation()` - opens UI 6. Call `setAdditionalContext()` - optional, after launching 7. Call `closeConversation()` or `startNewConversation()` - as needed 8. Call `destroy()` - on app shutdown When switching between modes (for example, from Service to Employee), calling `configure()` again with a different `type` automatically cleans up the previous client and conversation. ## Checking Configuration Status ```tsx // Check if configured const isConfigured = await AgentforceService.isConfigured(); // Get detailed configuration info const info = await AgentforceService.getConfigurationInfo(); if (info.configured) { console.log(`Configured in ${info.mode} mode`); } ``` ## See Also - [Conversations](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-react-native-conversations.md) - [Delegates](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-react-native-delegates.md) - [Employee Agent Authentication](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-react-native-employee-auth.md) - [Troubleshooting](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-react-native-troubleshooting.md) # Configure Voice Models in Agent Script Agentforce voice-enabled agents use a text-to-speech (TTS) voice model to convert an agent's responses into spoken audio. Each language has a default model, set by a lifecycle gate: most languages default to [ElevenLabs](https://elevenlabs.io/) v3 Conversational, and Japanese defaults to Kotoba. To select a different voice model, use the `modality voice` block in Agent Script. ## How Voice Selection Works An Agentforce Voice agent pairs two things: - **Voice model**: the TTS engine that generates speech, such as ElevenLabs v3 Conversational or Kotoba. - **Voice persona**: the specific voice (the tone, accent, and character) that the model speaks with. Agentforce Voice supports these TTS models. Choose the one that fits your agent: | Voice Model | Model ID | Choose it for | | :--------------------------- | :------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ElevenLabs v3 Conversational | `eleven_v3_conversational` | The most natural, expressive speech, and reliable pronunciation of entities like numbers, email addresses, and IDs. These voices are better than v2.5 for most languages. The default for most languages. | | ElevenLabs Flash v2 | `eleven_flash_v2` | The best custom pronunciation and better quality English than Flash v2.5, with steadier non-US English accents than v3 Conversational.  Honors the `speed`, `stability`, and `similarity` parameters. English locales only. | | ElevenLabs Flash v2.5 | `eleven_flash_v2_5` | The multilingual counterpart to Flash v2: the best adherence for secondary accents in non-English languages, such as Argentinian Spanish, French Canadian, and European Portuguese. Lower latency; honors the `speed`, `stability`, and `similarity` parameters. Doesn't support custom pronunciation. | | Kotoba | `kotoba` | Japanese speech. Kotoba is the default model for Japanese (`ja`). | v3 Conversational is the default for most languages. Flash v2 and Flash v2.5 aren't defaults, but they're fully supported. You select them in Agent Script when their latency, language, accent behavior, or custom pronunciation (Flash v2 only) fits your use case better than v3 Conversational. You can select a non-default model only in Agent Script. Agentforce Builder (Canvas) doesn't yet expose a voice-model selector, so v3 Conversational (the default) is the only model available there. To use Flash v2, Flash v2.5, or Kotoba on a non-default language, override the model in the `modality voice` block. ### Which Model Should I Use? Consider these tradeoffs when you choose between ElevenLabs v3 Conversational and the Flash models: - **ElevenLabs v3 Conversational** is the strongest all-around model and the default for most languages. It's the most expressive, and it pronounces entities like numbers, email addresses, and IDs correctly out of the box. However, it's less reliable with some non-US English accents, such as UK and Australian English. It doesn't use the `speed` or `similarity` parameters. `stability` defaults to 0.5. - **ElevenLabs Flash v2** is English-only and the best choice for English. It has the best custom pronunciation of any model, produces higher-quality English than Flash v2.5, and handles non-US English accents, such as UK and Australian English, more stably than v3 Conversational. It has lower latency and honors the `speed`, `stability`, and `similarity` parameters. Choose it when you want faster responses, fine-grained control over how a voice sounds, or reliable custom pronunciation for an English agent. - **ElevenLabs Flash v2.5** is the multilingual counterpart to Flash v2, for non-English languages. It gives the best adherence for secondary accents, such as Argentinian Spanish, French Canadian, and European Portuguese. It has lower latency and honors the `speed`, `stability`, and `similarity` parameters. It doesn't support custom pronunciation. If you need custom pronunciation and your agent is in English, use Flash v2. ### Choosing a Voice You choose a voice in two steps, because each voice persona belongs to a specific model: 1. **Choose a voice model.** To use a model other than the language default, set it in the `model` section of the `modality voice` block. 2. **Choose a voice persona from that model's voice list.** Each model publishes its own set of voices and the languages each voice supports. Find the voice you want in that model's list, and then set its **hash ID** as the `persona_id`. Use the hash ID as the identifier. The same voice used with a different model counts as a distinct voice, so match the hash ID to your selected model. See [Supported Voice Models](#supported-voice-models) for the voice list and supported languages for each model. Each language's default model is set through a lifecycle gate, so you can keep using the default without any changes. To use a different supported model, override the default in the `modality voice` block of your Agent Script. **note:** **Preview a voice before you commit to it.** To hear how a selected voice sounds, save your agent and use the agent preview to start a conversation. A voice sounds different in a live conversation than in a static sample, so the preview is the reliable way to evaluate it. When you set a voice model in Agent Script, don't switch back to Agentforce Builder (Canvas) to change the voice and then return to the script. Canvas and Agent Script use different underlying formats, and moving between them can leave your voice configuration in an inconsistent state. Change the voice model only when the language's default model doesn't meet your needs. The default is the recommended choice for most agents. ## Modality Voice Block The `modality voice` block defines how your agent speaks and listens. It has two directions, both optional. Configure only the ones you need: - `outbound`: how the agent speaks, including the voice persona, the text-to-speech (TTS) model, and model parameters such as speed and stability. - `inbound`: how the agent listens, including keyword and filler-word detection. The inbound speech-to-text (ASR) model isn't configurable. This example configures both directions: ```agentscript modality voice: outbound: persona_id: "8438b254ab85" # Lucie (fr), a Flash v2.5 voice model: id: "eleven_flash_v2_5" parameters: speed: 1.0 stability: 0.8 inbound: filler_words_detection: True keywords: - "urgent" - "emergency" ``` ### Outbound: How the Agent Speaks The `outbound` section sets the voice persona, the voice model, and any model parameters. ```agentscript modality voice: outbound: persona_id: "dd0c9186f164" # Olivia (en_US), a v3 Conversational voice ``` These properties make up the `outbound` section: | Property | Description | Default | | :----------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------- | | `persona_id` | Optional. The identifier of the voice persona the agent speaks with. Use the **hash ID** from the [Voice Catalog](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice-catalog.md) for your selected model. Omit to use the locale's default voice. | Locale default voice | | `model` | Optional. Selects and configures the voice model. Omit to use the language's default model. | Language default | | `model.id` | Optional. The model ID of the voice model to use, such as `eleven_flash_v2_5`. Omit to use the language's default model. See [Supported Voice Models](#supported-voice-models) for the available model IDs. | Language default | | `model.parameters` | Optional. Model-specific settings passed through to the voice model. See [Model Parameters](#model-parameters). | — | ### Model Parameters `model.parameters` is an open passthrough. You can set any name-value pairs, such as strings, booleans, or numbers, and Agent Script forwards them to the model at runtime. Agent Script doesn't validate parameter names or value ranges: which parameters a model honors, and their valid ranges, are defined by the model itself. Setting a parameter that a model doesn't recognize has no effect. These parameters are commonly used with the ElevenLabs voice models. Treat this as a starting point, not a complete or enforced list. Each voice persona ships with its own tuned defaults for these parameters, so a value that sounds right for one persona isn't the default for another. Omit a parameter to use the persona's default, and set one only when you want to override it. The ranges below apply to the ElevenLabs Flash v2.5 and Flash v2 models, which honor these parameters. ElevenLabs v3 Conversational doesn't use `speed` or `similarity`, so their ranges don't apply to it. | Parameter | Description | Range | | :----------- | :----------------------------------------------------------------------------------------------------------------------------- | :------ | | `speed` | How fast the voice speaks. Lower values slow the speech down; higher values speed it up. | 0.7–1.2 | | `stability` | How consistent the delivery is. Lower values give a more expressive, variable performance; higher values give steadier speech. | 0–1 | | `similarity` | How closely the output matches the original voice's character. Higher values stay closer to the source voice. | 0–1 | How a model applies these parameters varies: - **ElevenLabs Flash v2.5 and Flash v2** honor `speed`, `stability`, and `similarity`. Use a Flash model when you need precise control over how a voice sounds. - **ElevenLabs v3 Conversational** doesn't use `speed` or `similarity`. `stability` defaults to 0.5. - **Kotoba** doesn't take these parameters. Select the model and a persona without a `parameters` block. ### Inbound: How the Agent Listens The `inbound` section configures how the agent detects what the customer says. The inbound speech-to-text (ASR) model ID isn't configurable. You can't set or change it in the `modality voice` block. ```agentscript modality voice: inbound: filler_words_detection: True keywords: - "urgent" - "emergency" ``` These properties make up the `inbound` section: | Property | Description | Default | | :----------------------- | :---------------------------------------------------------------------------------------------------------------- | :------ | | `filler_words_detection` | Optional. When `True`, the agent detects and ignores filler words such as "um" and "uh" in the customer's speech. | `False` | | `keywords` | Optional. A list of keywords to boost during recognition, which improves accuracy for domain-specific terms. | — | ## Select the Flash v2 Voice Model Flash v2 is the English-only, lower-latency model, and it's the best choice for English agents. It has the best custom pronunciation of any model and handles non-US English accents, such as UK and Australian English, more stably than v3 Conversational. Like Flash v2.5, it honors the `speed`, `stability`, and `similarity` parameters. To use it, specify the Flash v2 model and a compatible English voice persona in the `modality voice` block. No other Agent Script blocks need to change. Use Flash v2 for English. For other languages, use Flash v2.5 instead. ```agentscript modality voice: outbound: persona_id: "a029af9d692c" # April (en_US), a Flash v2 voice model: id: "eleven_flash_v2" parameters: speed: 1.0 stability: 0.8 similarity: 0.75 ``` ## Select a Flash v2.5 Voice Model Flash v2.5 is the multilingual, lower-latency model, so it's a good fit for non-English languages when you want faster spoken responses. It gives the best adherence for secondary accents, such as Argentinian Spanish, French Canadian, and European Portuguese. Unlike v3 Conversational, it honors the `speed`, `stability`, and `similarity` parameters, so choose it when you also want fine-grained control over how a voice sounds. Flash v2.5 doesn't support custom pronunciation. To use it, specify the Flash v2.5 model and a compatible Flash v2.5 voice persona in the `modality voice` block. No other Agent Script blocks need to change. Use Flash v2.5 for non-English languages. For English, use Flash v2 instead. ```agentscript modality voice: outbound: persona_id: "4f708167ff27" # Louis (fr), a Flash v2.5 voice model: id: "eleven_flash_v2_5" parameters: speed: 1.0 stability: 0.8 similarity: 0.75 ``` ## Select the Kotoba Voice Model for Japanese Kotoba is the default voice model for Japanese (`ja`), so you don't need to select it explicitly for a Japanese agent. To set it in a per-language configuration, specify the model and a compatible Japanese voice persona. Kotoba doesn't take voice parameters, so omit the `parameters` block. ```agentscript modality voice: language: default_locale: "ja" language_settings: ja: outbound: persona_id: "e5d63b40f254" # Azawa (ja), a Kotoba voice model: id: "kotoba" ``` ## Legacy Voice Format Some existing scripts use an older, flat format that sets a voice and speed directly, without the `outbound` and `model` nesting: ```agentscript modality voice: voice_id: "" outbound_speed: 0.9 ``` This format still works, so scripts that use it keep running without changes. But it can't select a voice model such as Flash v2.5. Model selection exists only in the nested format. For any new voice configuration, use the nested format shown earlier. **important:** You can't combine the two formats in one script. If you move a script to the nested format, rewrite the entire `modality voice` block. There's no automatic conversion. ## Supported Voice Models Agentforce Voice supports these voice models. Specify a model by its model ID in the `modality voice` block. | Voice Model | Model ID | Availability | Voice List | | :--------------------------- | :------------------ | :------------------------------------------------------------------------ | :-------------------------------------------------------------------------------- | | ElevenLabs v3 Conversational | `eleven_v3_conversational` | Default for most languages. Available in Canvas and Agent Script. | [ElevenLabs v3 Conversational Voices](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice-catalog-v3-conversational.md) | | ElevenLabs Flash v2.5 | `eleven_flash_v2_5` | Multilingual, for non-English languages. Selectable in Agent Script only. | [ElevenLabs Flash v2.5 Voices](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice-catalog-flash-2-5.md) | | ElevenLabs Flash v2 | `eleven_flash_v2` | English only. Selectable in Agent Script only. | [ElevenLabs Flash v2 Voices](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice-catalog-flash-2.md) | | Kotoba | `kotoba` | Japanese (`ja`) only. The default model for Japanese. | [Kotoba Voices](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice-catalog-kotoba.md) | The default model for each language is set by a lifecycle gate. When you don't select a model, the agent uses that language's default. To use a non-default model, select it in the `modality voice` block. Canvas doesn't yet expose a voice-model selector. For how each model handles voice parameters, see [Model Parameters](#model-parameters). ## Voice Lists Each model has its own catalog of voice personas, and each voice supports specific locales: - [ElevenLabs v3 Conversational Voices](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice-catalog-v3-conversational.md) - [ElevenLabs Flash v2 Voices](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice-catalog-flash-2.md) - [ElevenLabs Flash v2.5 Voices](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice-catalog-flash-2-5.md) - [Kotoba Voices](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice-catalog-kotoba.md) For all lists on one page, see the full [Voice Catalog for Agentforce Voice](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice-catalog.md). To set a voice, find it in the list for your selected model and use its hash ID as the `persona_id`. If you don't set a `persona_id`, the agent uses the locale's default voice, marked **(default)** in the voice list. ## Considerations - Existing agents and existing Agent Script continue to work without changes. To use the new voice capabilities, rewrite the `modality voice` block. - You can't mix the legacy and nested voice formats in the same script. - Agentforce Builder (Canvas) doesn't expose a voice-model selector, doesn't show the voice catalog for non-default models, and doesn't filter its voice picker based on an Agent Script override. ## Related Topics - [Agent Script Blocks](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-blocks.md) - [Agent Script Reference](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-reference.md) - [ElevenLabs](https://elevenlabs.io/) # Connect API Resources for Testing API The Connect API endpoints for Testing API execute test cases, poll for results, and programmatically retrieve detailed test results. ## Start Test Start a test asynchronously based on the provided AiEvaluationDefinition name or ID. This endpoint schedules the test and returns an identifier to track its progress. OAuth 2.0 with a connected app is required. See the [Connect REST API Quick Start](https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/quickstart.htm). ### Resource ``` /services/data/v63.0/einstein/ai-evaluations/runs ``` #### HTTP Methods `POST` ### Request #### Headers ```bash { "Content-Type": "application/json", "Authorization": "Bearer " } ``` #### Parameters ```bash { "aiEvaluationDefinitionName": "" } ``` The API enforces that exactly one of the two parameters is provided. If no parameters or multiple parameters are provided, the API returns a `400 Bad Request` response code with an empty error message. | Parameter Name | Type | Description | | :--------------------------- | :----- | :-------------------------------------------------------------------- | | `aiEvaluationDefinitionName` | string | Required. The name (`DeveloperName`) of the test definition to start. | ### Response HTTP response code: 200 ```json { "runId": "", "status": "" } ``` | Parameter Name | Type | Description | | :------------- | :----- | :-------------------------------------- | | `runId` | string | The unique ID of the test that started. | ## Get Test Status Retrieves the operational status of a specified test. We designed this endpoint to poll to monitor the progress of a test. ### Resource ``` /einstein/ai-evaluations/runs/:runId ``` #### HTTP Methods `GET` ### Request #### Headers ```bash { "Authorization": "Bearer " } ``` #### Parameters | Parameter Name | Type | Description | | :------------- | :----- | :-------------------------------------------- | | `runId` | string | Required. The unique identifier for the test. | ### Response ```json { "status": "", "startTime": "", "endTime": "", "errorMessage": "" } ``` | Parameter Name | Type | Description | | :------------- | :----------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `status` | enum |
  • NEW: The test was created but not yet started.
  • IN_PROGRESS: The test is currently executing.
  • COMPLETED: The test finished successfully.
  • ERROR: At least one test case encountered an operational error.
| | `startTime` | ISO 8601 timestamp | The timestamp indicating when the test started. | | `endTime` | ISO 8601 timestamp | The timestamp indicating when the test ended. `endTime` is null if the test hasn't ended yet. | | `errorMessage` | string | The details of the error if the status is ERROR. `errorMessage` is empty if no error occurred. | ## Get Test Results Retrieve a detailed report of a test, including information on each test case and the results of all predetermined expectations. ### Resource ``` /einstein/ai-evaluations/runs/:runId/results ``` #### HTTP Methods `GET` ### Request #### Headers ```bash { "Authorization": "Bearer " } ``` #### Parameters | Parameter Name | Type | Description | | :------------- | :----- | :------------------------------------------- | | `runId` | string | Required. The unique identifier of the test. | ### Response ```json { "status": "", "subjectName": "", "startTime": "", "endTime": "", "errorMessage": "", "testCases": [ { "status": "", "testNumber": "", "startTime": "", "endTime": "", "errorMessage": "", "inputs": { "utterance": "" }, "generatedData": { "actionsSequence": "", "outcome": "", "topic": "" }, "testResults": [ { "name": "", "actualValue": "", "expectedValue": "", "metricScore": "", "metricLabel": "", "metricExplainability": "", "status": "", "startTime": "", "endTime": "", "errorCode": "", "errorMessage": "" } ] } ] } ``` #### Response Object | Parameter Name | Type | Description | | :------------- | :----------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `status` | enum |
  • NEW: The test was created but not yet started.
  • IN_PROGRESS: The test is currently executing.
  • COMPLETED: The test finished successfully.
  • ERROR: At least one test case encountered an operational error.
| | `startTime` | ISO 8601 timestamp | The timestamp indicating when the test started. | | `endTime` | ISO 8601 timestamp | The timestamp indicating when the test ended. `endTime` is null if the test hasn't ended yet. | | `errorMessage` | string | The details of the error if the status is ERROR. `errorMessage` is empty if no error occurred. | | `testCases` | TestCaseObject | Represents the test cases being evaluated. | #### testCase Object | Parameter Name | Type | Description | | :------------- | :------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | status | enum |
  • NEW: The test has been created but not yet started.
  • IN_PROGRESS: The test is currently executing.
  • COMPLETED: The test finished successfully.
  • ERROR: At least one test case encountered an operational error.
| | testNumber | integer | The number of the test case. | | subjectName | string | A unique identifier for the subject. This should be the `DeveloperName` of the `AiEvalDefinition` entity. | | startTime | ISO 8601 timestamp | The timestamp indicating when the test started. | | endTime | ISO 8601 timestamp | The timestamp indicating when the test ended. `endTime` is null if the test hasn't ended yet. | | errorMessage | string | Details of the error if the status is ERROR. `errorMessage` is empty if no error occurred. | | inputs | InputsObject | Represents the inputs sent to the agent. | | generatedData | GeneratedDataObject | Represents the data that was generated by the subject during the test and was used to evaluate the expectations. | | testResults | array\[TestResultObject\] | Includes the results of each test. | #### inputs Object | Parameter Name | Type | Description | | :------------- | :----- | :------------------------------- | | utterance | string | The utterance sent to the agent. | #### generatedData Object | Parameter Name | Type | Description | | :-------------- | :-------------- | :----------------------------------------------- | | actionsSequence | array\[string\] | A sequence of actions performed during the test. | | outcome | string | The response of the subject under test. | | topic | string | The subagent used by the subject during testing. | #### testResult Object | Parameter Name | Type | Description | | :------------------- | :----------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | name | string | The name of the test metric. | | actualValue | string | The actual value obtained during the test. | | expectedValue | string | The expected value for the metric. | | metricScore | enum | The outcome for the metric. Values: `PASS`, `FAILED`. For `instruction_adherence` only: `HIGH`, `LOW`, `UNCERTAIN`. | | metricLabel | string | The metric name. | | metricExplainability | string | A detailed explanation of the metric's purpose and test criteria. | | metricType | string | The name of the test metric. | | status | string |
  • NEW: The test has been created but not yet started
  • IN_PROGRESS: The test is currently executing
  • COMPLETED: The test finished successfully
  • ERROR: At least one test case encountered an operational error
| | startTime | ISO 8601 timestamp | The timestamp when the test of this metric started. | | endTime | ISO 8601 timestamp | The timestamp when the test of this metric ended. | | errorCode | string or null | The error code if an error occurred during the test; otherwise, null. | | errorMessage | string or null | A detailed error message if an error occurred during the test; otherwise, null. | # Considerations for the Testing API Review these considerations before you use Testing API. ## Einstein Requests Usage Einstein Requests is a usage metric for generative AI. The use of generative AI capabilities, in either a production or sandbox environment, consumes Einstein Requests credits and possibly Data 360 credits. See [Generative AI Billable Usage Types](https://help.salesforce.com/s/articleView?id=ai.generative_ai_usage.htm&type=5). ## In-Progress Run Limit You can have up to 10 `IN-PROGRESS` runs at any time. ## Maximum Test Cases in AiEvaluationDefinition In an `AiEvaluationDefinition` component in Metadata API, the maximum number of test cases is 1,000. ## Test Results May Change When Rerun Because of continuous improvements to the testing service, sometimes test results may change. # ConversationUIContainer ## Overview The main conversation interface container for the Agentforce SDK. A SwiftUI view that provides a complete conversational AI interface with message display, user input, voice interaction, and multi-modal content. ## Declaration ```swift @MainActor struct ConversationUIContainer ``` ## Properties | Property | Type | Description | | ---------------- | ----------- | ----------------------------------------------------------- | | `body` | `some View` | The main view content (inherited from View) | | `alternateTitle` | `String?` | Optional custom title to display in the conversation header | ## Methods | Method | Signature | Description | | ------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | `updateSession(session:)` | `func updateSession(session: AgentConversation) throws` | Updates the conversation session with a new session instance | | `sendUtterance(_:)` ⚠️ | `func sendUtterance(_ utterance: String)` ⚠️ | **Deprecated:** Messages should be sent using [AgentforceConversation.sendUtterance](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-conversation-ios.md#sendutterance) | | `resetChat()` ⚠️ | `func resetChat()` ⚠️ | **Deprecated:** The chat should be cleared using [AgentforceConversation.reset](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-conversation-ios.md#reset) | | _Inherited from View_ | _All View protocol methods_ | Inherits all standard SwiftUI View methods and modifiers. See [View (_Apple Developer_)](https://developer.apple.com/documentation/swiftui/view) | ## Integration Patterns ### Modal Presentation ```swift .sheet(isPresented: $showConversation) { ConversationUIContainer( viewModel: conversationViewModel, flagProvider: featureFlags, onClose: { showConversation = false } ) } ``` ### Navigation Integration ```swift NavigationView { ConversationUIContainer( viewModel: conversationViewModel, flagProvider: featureFlags, onClose: { navigationController.popViewController() } ) } ``` ### Full-Screen Presentation ```swift .fullScreenCover(isPresented: $showFullScreen) { ConversationUIContainer( viewModel: conversationViewModel, flagProvider: featureFlags, onClose: { showFullScreen = false } ) } ``` # Core Classes The Agentforce Mobile SDK for Android provides core classes that form the foundation of the SDK functionality. ## AgentforceClient The main client class for initializing and managing the Agentforce SDK. ## AgentforceConversation The conversation management class that handles chat interactions and conversation state. ## Related Topics - [AgentforceClient](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-client-android.md) - [AgentforceConversation](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-conversation-android.md) # Core Classes The Agentforce Mobile SDK for iOS provides core classes that form the foundation of the SDK functionality. ## AgentforceClient The main client class for initializing and managing the Agentforce SDK. ## AgentforceConversation The conversation management class that handles chat interactions and conversation state. ## Related Topics - [AgentforceClient](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-client-ios.md) - [AgentforceConversation](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-conversation-ios.md) # Create a Non-Agent Script Agent From a Spec (Legacy) **warning:** This section describes the process of creating agents _directly_ from an agent spec YAML file, rather than creating agents that use Agent Script as their blueprint. We don't recommend that you use this legacy workflow anymore to create an agent. Instead, we recommend that you author agents that use the Agent Script language, which is the next-gen way of creating agents. See [Author an Agent with Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-nga-author-agent.md). After you have an agent spec file that you like, it’s time to create the agent in your development org, such as your sandbox. Let’s say you want to create an agent with the name (label) **Resort Manager** and you previously generated its agent spec file using its default filename (`specs/agentSpec.yaml`). ## Preview the Agent Without Updating Your Development Org Before actually updating your development org, let’s first preview what the agent will look like when created in the org. From VS Code’s integrated terminal, run this command: ```bash sf agent create --spec specs/agentSpec.yaml --name "Resort Manager" --preview --target-org ``` If you’ve set a default org in your DX project, such as your sandbox, you don’t need to specify `--target-org`. You can also run this command from your DX project using a terminal (macOS, Linux) or command prompt (Windows). The command prompts you for the API name of the agent; we recommend that you accept the default. The command generates a JSON file with name `Resort_Manager_Preview_.json`. The JSON file describes the agent that the LLM creates, including suggested actions for each subagent, instructions, and sample utterances. If it all looks good to you, it’s time to create the agent in your org. ## Create the Agent in Your Development Org From VS Code’s integrated terminal, run the same command you ran to preview the agent creation, but this time remove the `--preview` flag: ```bash sf agent create --spec specs/agentSpec.yaml --name "Resort Manager" --target-org ``` As before, the command prompts you for the new agent’s API name (in this case `Resort_Manager`); we recommend that you accept the default. The command then displays the steps that it performs. Steps include parsing the agent spec file, creating the agent in the development org, and retrieving the metadata that was created in the org back to the local DX project. Here’s partial sample output from the command: ```bash ────────── Creating Resort Manager Agent ────────── ✔ Parsing Agent spec 36ms ✔ Creating Agent in org 17.55s ✔ Retrieving Agent metadata 3ms Elapsed Time: 17.81s Successfully created Resort Manager in epic.4bec8e502a0c@fakeorg.out. ``` Your development org has now been updated with the **Resort Manager** agent and your local DX project has been synchronized with all its associated metadata. Run this CLI command to open the new agent in your org’s Agentforce Builder UI: ```bash sf org open agent --api-name Resort_Manager ``` The `--api-name` flag of `org open agent` uses the API name of an agent; to find an agent's API name, go to Setup in your org and go to the agent's details page. Now that you’ve created a basic agent, it’s time to customize it and implement the details of what it can do. ## See Also - [_Salesforce CLI Command Reference_: agent Commands](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_agent_commands_unified.htm) - [_Salesforce Extensions for Visual Studio Code_](https://developer.salesforce.com/docs/platform/sfvscode-extensions/guide) # Create Actions from Apex Controller Methods Quickly create an OpenAPI document for your Apex controller methods and activate the API for use in Agentforce. Deploy the class, the OpenAPI document, and associated metadata to your org’s API catalog. Then create an agent action in Agentforce Builder in your org that’s based on methods in the class. ## Generate an OpenAPI Specification (OAS) for an Apex Class Salesforce's OpenAPI Specification (OAS) generation feature uses the [Agentforce Vibes Extension](https://developer.salesforce.com/docs/platform/einstein-for-devs/guide/einstein-overview.html). Agentforce Vibes Extension is an AI-powered extension built using `CodeGen` and `xGen-Code`, secure, custom AI models from Salesforce. This feature generates OpenAPI v3 Specifications for Apex classes that define controller methods annotated with `@AuraEnabled`. You can then deploy the generated OAS to add it to the Salesforce API catalog. The API then becomes available to create custom actions and can be used by Agentforce agents to enhance their capabilities. ## See Also - [Apex AuraEnabled Annotation](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_annotation_AuraEnabled.htm) - [Lightning Aura Components Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_annotation_AuraEnabled.htm) - [Lightning Web Components Developer Guide](https://developer.salesforce.com/docs/platform/lwc/guide) # Create Actions from Named Query API | USER PERMISSIONS NEEDED | | | ------------------------------------------------------- | --------------------------------------------------------------------------- | | To work with Named Query API: | **Allows users to create, read, update and delete Named Query API records** | | To use an agent with actions based on Named Query APIs: | Either **View Developer Name** or **View Setup and Configuration** | With Named Query API, you can create custom SOQL queries (Named Query APIs) in Setup, then expose them as agent actions in Agent Creator. ## Enable Named Query APIs for Agent Actions 1. From Setup, in the Quick Find box, enter `User Interface` and then select **User Interface**. 2. On the User Interface page, select **Enable Salesforce Platform REST API, Named Query for Agent Actions**. After you create a Named Query API, it appears in **Setup** > **[API Catalog](https://help.salesforce.com/s/articleView?id=platform.api_catalog_view_apis.htm&type=5)**. You must manually activate the Named Query APIs in the API Catalog to make them available as agent actions. ## Use Named Query APIs as Agent Actions Create and save Named Query APIs to make them available as agent actions. See [Named Query API](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_named_query.htm) in the _REST API Developer Guide_. To access a Named Query API in Agent Creator, follow these steps. 1. From Setup, in the Quick Find box, enter `assets`, and then select **Agentforce Assets**. 2. Click **Actions** in the Agentforce Asset Library. 3. Click **New Agent Action**. 4. Select **API** from Reference Action Type. 5. Select **Salesforce Named Query API** from Reference Action Category. 6. Select an action from Reference Action. **note:** Users executing named queries must have read access to the data being queried. # Create Agent Actions from API Operations Use an AuraEnabled Apex class retrieved from your org to generate an OpenAPI document and External Services Registration metadata. Then deploy the OpenAPI document to create API operations that you activate for use as agent actions. ## Use the Org Browser to Retrieve Existing Apex AuraEnabled Metadata Before you generate an OpenAPI spec document from AuraEnabled Apex classes, retrieve the classes into your VS Code project. The Org Browser displays all the metadata types in your connected org and makes it easy to retrieve any metadata component. Use the org browser to navigate to your existing AuraEnabled Apex classes for which you want to generate the OpenAPI specification (OAS) document. Click the retrieve icon next to the metadata type to quickly retrieve the required classes. The retrieved classes are located in the `/force-app/main/default/classes` in your Salesforce project. See [Org Browser](https://developer.salesforce.com/docs/platform/sfvscode-extensions/guide/org-browser.html) to learn more. ## Generate OpenAPI Documents 1. Run **SFDX: Create OpenAPI Document from this Class (Beta)** from the command palette or the context menu. 2. In the search bar, enter the folder where you want to store the generated files or accept the default `externalServiceRegistration` folder. The command generates the files `.yaml`, and `.externalServiceRegistration-meta.xml`. **note:** The description that appears in your org's API catalog comes from the top-level description mapping in the YAML file, not the `` element of the XML file. 3. Run the **SFDX: Deploy This Source to Org** command on the generated XML file to deploy the metadata to your org. The command to deploy isn't ‌available on the YAML file. If the command times out, try again at a later time. ### Regenerate OpenAPI Documents You can regenerate an OpenAPI document if you modify the Apex class associated with it. 1. Make the changes to the Apex class associated with the OpenAPI document. 2. Run the **SFDX: Create OpenAPI Document from this Class (Beta)** command. 3. Select **Overwrite** or **Manually merge with existing ESR** from the window. **Overwrite** directly overwrites the existing OpenAPI document; this action is irreversible. The **Manually Merge with Existing ESR** option opens a diff window comparing the original and new OpenAPI documents. The new files are generated with the naming format: `_.externalServiceRegistration-meta.xml` and `_.yaml`.These files are located in the `esr_files_for_merge` folder in the root directory of your Salesforce project. 4. Check the Problems tab for any errors or warnings in the new OpenAPI document (identified by the timestamp) and manually merge the changes from the newly generated OpenAPI document into the original document. 5. Run the **SFDX: Validate OpenAPI Document (Beta)** command on the merged or overwritten OpenAPI document. 6. Deploy the validated OpenAPI document to your Salesforce org. **note:** You may encounter API Catalog limits when deploying. See [Limits](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-auraenabled-limits.md). ## Confirm the API Registration in the API Catalog The OpenAPI document you deploy to your org describes the AuraEnabled API. After deployment, your API and its operations are registered in your org's API catalog. 1. In your org, from **Setup**, in the **Quick Find** box, enter `API Catalog` and select it. See [View Apex APIs in API Catalog](https://help.salesforce.com/s/articleView?id=platform.api_catalog_view_apex_apis.htm&type=5). 2. To view AuraEnabled APIs, select the **AuraEnabled** list as the source. 3. Click the AuraEnabled API you created to view its operations. 4. Activate operations to make them available for creating agent actions. ## Create Agent Actions 1. In your org, from **Setup**, in the **Quick Find** box, enter `Agentforce Studio`. 2. In the Agentforce Asset Library, click **New Agent Action**. The API and its operations are available as an Apex Reference Action type that you use to [create a custom agent action](https://help.salesforce.com/s/articleView?id=ai.copilot_actions_custom.htm&type=5). ![Apex tab in API catalog](https://developer.salesforce.com/media/api-catalog-apex-auraenabled.png '{"class": "image-full image-framed"}') # Create an Agent Test from the Spec File **warning:** This section describes the legacy process for testing Agentforce agents, or the pro-code equivalent to using the [Legacy Agentforce Testing Center in Setup](https://help.salesforce.com/s/articleView?id=ai.agent_testing_center_setup_tests.htm&type=5). It doesn't apply to the new agent testing process, or the pro-code equivalent to the [New Testing Center in Agentforce Studio (Beta)](https://help.salesforce.com/s/articleView?id=ai.agent_studio_testing_center_setup_tests.htm&type=5). That documentation will be released soon. Once you have a test spec file that you like, it’s time to create the test in your development org. You must publish the agent to your org before you can create a test using the `agent test create` CLI command. ## Preview the Agent Test Without Updating Your Org Before updating your development org with the new agent test, let’s first preview what it looks like when deployed to your org by generating a local AiEvaluationDefinition metadata XML file. From the VS Code integrated terminal, run this command: ```bash sf agent test create --preview --target-org ``` If you’ve set a default org in your DX project, such as your sandbox, don’t specify `--target-org`. You can also run this command from your DX project by using a terminal (macOS, Linux) or command prompt (Windows). The `agent test create --preview` command prompts you to enter an API name for the new test. Be sure that you specify a name that doesn’t exist in your org. You’re then prompted to select the agent spec file from the ones available in your DX project. When the command finishes, it makes a preview metadata XML file in the current directory for the new AiEvaluationDefinition component. This component represents an agent test in your org. The file is called `{Test_Api_name}-preview-{timestamp}.xml`. If the file looks good to you, it’s time to create the agent test in your org. ## Create Agent Tests In Your Development Org Run the `agent test create` command you used to preview the test, but don’t specify `--preview`. ```bash sf agent test create --target-org ``` As with previewing, the command prompts you for the API name of your new test and the test spec file that you want to use. If you prefer, you can also pass these values by using the `--spec` and `--api-name` flags. The command then displays the execution stages, such as creating local metadata and deploying to the development org. After the command finishes executing, your org is updated with the new agent test. Your local DX project is also synchronized with the associated metadata file (AiEvaluationDefinition) in the package directory. To view the deployed test in the Testing Center UI of your development org, open the UI in a browser. ```bash sf org open --path /lightning/setup/TestingCenter/home --target-org username-or-alias ``` ## See Also - [Publish Your Agent](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-nga-publish.md) - [_Salesforce CLI Command Reference_: agent Commands](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_agent_commands_unified.htm) - [_Salesforce Extensions for Visual Studio Code_](https://developer.salesforce.com/docs/platform/sfvscode-extensions/guide) - [_Salesforce Help_: Agentforce Testing Center](https://help.salesforce.com/s/articleView?id=ai.agent_testing_center.htm&type=5) # Create an Agent Without Using Agent Script (Legacy) **warning:** This section describes the process of creating agents _directly_ from an agent spec YAML file, rather than creating agents that use Agent Script as their blueprint. We don't recommend that you use this legacy workflow anymore to create an agent. Instead, we recommend that you author agents that use the Agent Script language, which is the next-gen way of creating agents. See [Author an Agent with Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-nga-author-agent.md). Creating an agent directly with Agentforce DX is a two-step process; each step uses a Salesforce CLI command: 1. `agent generate agent-spec`: [Generate an agent spec file](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-generate-agent-spec.md) in your Salesforce DX project. An agent spec is a YAML file that contains information about the agent. 2. `agent create`: [Create the agent](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-create-agent-spec.md) in your development org, such as your sandbox. The create command takes the agent spec file as input. The command syncs the metadata back to your DX project. After running these two commands, the resulting agent is basic. It’s more a _scaffold_ of an agent rather than a finished one. As with all software development, you then go through an iterative process to create a complete agent that you can activate for your users. Agentforce DX gets you started on this journey. ## See Also - [_Trailhead_: Agentforce Basics](https://trailhead.salesforce.com/content/learn/modules/einstein-copilot-basics) - [_Salesforce CLI Command Reference_: agent Commands](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_agent_commands_unified.htm) - [_Salesforce Help_: Design and Implement Agents](https://help.salesforce.com/s/articleView?id=ai.copilot_intro.htm) # Create an Agentforce-Ready Scratch Org With Salesforce CLI This guide describes the basic steps for using Salesforce CLI to create a generative AI scratch org for a Developer or Enterprise edition org. You can use either a [sandbox or a scratch org](https://developer.salesforce.com/docs/ai/agentforce/guide/agentforce/agent-dx/agent-dx-set-up-env.md#sandbox-versus-scratch-org) to develop and test your agents. If your agent needs Agentforce Data Library (ADL) or other Data 360 features, we recommend using a sandbox. For more information on the Agentforce developer lifecycle, see [Build Agents with Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/guide/agentforce/agent-dx/agent-dx.md) **note:** A [scratch org](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs.htm) is a configurable, short-term Salesforce environment that you can quickly spin up when starting a new project, a new feature branch, or a feature test. Unlike a sandbox, a scratch org doesn't contain data or metadata from your production org. Scratch orgs are configured using a scratch org definition file, which lists the features and settings that mirror the customer's production org. 1. Install [Salesforce CLI](https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli.htm) on your computer. 2. Open a terminal (macos, Linux) or command prompt (Windows) and make sure that Salesforce CLI is up to date by running this command. ```bash sf update ``` 3. (Optional) [Create a Salesforce DX project](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_ws_create_new.htm) on your computer and change to the directory. If you only want to create a scratch org, then this step isn't necessary. But we recommend creating a DX project if you plan to store your org’s metadata (code and configuration), org templates, sample data, and tests in a version control system. See [Project Setup](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_workspace_setup.htm). 4. Select and enable your Dev Hub org, which must have your Data 360 licenses. See [Select and Enable a Dev Hub Org](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_setup_enable_devhub.htm) in the Salesforce DX Developer Guide for more information. 5. Log in to your Dev Hub org and allow access. In the browser window that opens, sign in to your org with your Salesforce login credentials. Click **Allow**, which allows Salesforce CLI to access to your org. ```bash sf org login web --set-default-dev-hub --alias DevHub ``` 6. Create a definition file, such as `afdx-scratch-def.json`. If you're using a Salesforce DX project, create the file in the `config` directory alongside the existing `config/project-scratch-def.json` file. To use an Einstein Generative AI scratch org, add the `Einstein1AIPlatform` feature, which is supported in Developer and Enterprise editions. To automatically enable Einstein and Agentforce, turn on the `agentPlatformSettings.enableAgentPlatform` and `einsteinGptSettings.enableEinsteinGptPlatform` settings. ```json { "orgName": "Agentforce scratch org", "edition": "Developer", "features": ["EnableSetPasswordInApi","Einstein1AIPlatform"], "settings": { "lightningExperienceSettings": { "enableS1DesktopEnabled": true }, "mobileSettings": { "enableS1EncryptedStoragePref2": false }, "agentPlatformSettings": { "enableAgentPlatform": true }, "einsteinGptSettings" : { "enableEinsteinGptPlatform" : true } } } ``` 7. Using the scratch org definition file, create the scratch org. ```bash sf org create scratch --definition-file config/afdx-scratch-def.json --alias MyScratchOrg --set-default --target-dev-hub DevHub ``` 8. Open the org. ```bash sf org open --target-org MyScratchOrg ``` After you open the org, you can use Salesforce generative AI features such as Agentforce, Prompt Builder, Model Builder, and the Models API. To learn more, see [Agentforce and Einstein Generative AI](https://help.salesforce.com/s/articleView?id=ai.generative_ai.htm) in Salesforce Help. ## See Also - [Set Up Einstein Generative AI and Agentforce](https://developer.salesforce.com/docs/ai/agentforce/guide/org-setup.md) - [AgentPlatformSettings Metadata API](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_agentplatformsettings.htm) - [EinsteinGptSettings Metadata API](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_einsteingptsettings.htm) # Create Custom Actions Using Apex Invocable Method With Agentforce Builder, developers can enhance agent capabilities by creating custom actions using Apex, flows, or prompt templates. This unique extensibility empowers developers to tailor agents to their business needs. To use your Apex code in a custom action, you can annotate your method with `@InvocableMethod`. This annotation makes the action available for configuration in Agentforce Builder. The following sample code shows an Apex class that uses this annotation. ```apex public with sharing class HelloWorld { @InvocableMethod(label='Hello World' description='Takes a name and returns a greeting message') public static List sayHello(List inputs) { List outputs = new List(); for (InputParameters input : inputs) { OutputParameters output = new OutputParameters(); output.greeting = 'Hello, ' + input.name + '!'; outputs.add(output); } return outputs; } public class InputParameters { @InvocableVariable(required=true label='Name' description='The name of the person to greet') public String name; } public class OutputParameters { @InvocableVariable(label='Greeting' description='The greeting message') public String greeting; } } ``` To learn how to turn an invocable method into a custom action in Agentforce, review these resources. **Salesforce Help** - _Salesforce Help_: [Agent Actions](https://help.salesforce.com/s/articleView?id=ai.copilot_actions.htm) - _Salesforce Help_: [Use Agentforce to Invoke External Service Actions](https://help.salesforce.com/s/articleView?id=platform.external_services_custom_agent_actions.htm) **Developer Blog** - _Developer Blog_: [Build Custom Agent Actions Using Apex](https://developer.salesforce.com/blogs/2024/03/build-custom-copilot-actions-using-apex) - _Developer Blog_: [Best Practices for Building Agentforce Apex Actions](https://developer.salesforce.com/blogs/2025/07/best-practices-for-building-agentforce-apex-actions) **Developer Reference** - _Apex Developer Guide_: [InvocableMethod Annotation](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_annotation_InvocableMethod.htm) # Create Custom Scorers for Agent Testing Custom scorers allow you to define evaluation logic for agent testing. [Standard Expectations](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-use-results.md) cover common test scenarios like topic matching and response coherence, but custom scorers create expectations tailored to your business requirements. Custom scorers evaluate agent behavior at different levels of granularity. A custom scorer can test an entire conversation, a single interaction, or a specific moment within an interaction. Scorers use a prompt template to evaluate agent behavior automatically with an LLM. Use the `AiAgentScorerDefinition` Metadata API type to define custom scorers and deploy them to your org. ## How Custom Scorers Work A custom scorer evaluates agent behavior and produces a result that maps to an outcome: pass, fail, or not applicable. Each scorer has two key components: - **Engine**: The evaluation logic. Use a `PromptTemplate` engine to assess the agent's behavior with an LLM. - **Output mapping**: Rules that translate the engine's result into a pass, fail, or not-applicable outcome. In this guide, we define a custom scorer that uses a prompt template to detect whether a customer dropped off before the conversation resolved. ## Prerequisites - Agentforce is enabled in your org with at least one active agent. See [Set up Agents](https://help.salesforce.com/s/articleView?id=ai.copilot_setup.htm) in Salesforce Help. - If your scorer uses the `PromptTemplate` engine type, the prompt template must exist in your org or get deployed alongside the scorer. See [Deploy a Scorer with a Prompt Template](#deploy-a-scorer-with-a-prompt-template) for details on deploying both together. ## `AiAgentScorerDefinition` Reference Create an `AiAgentScorerDefinition` metadata component to define your scorer. The component exists in the `aiAgentScorerDefinitions` folder with the `.aiAgentScorerDefinition` file suffix. ### `inputScope` The scorer defines two `inputScope` fields that work together to control what data the scorer evaluates: | Field | Valid values | Description | | ----------------------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------- | | Top-level `inputScope` | `Session` | The data the scorer's evaluation logic (its prompt template or manual scores) operates on. | | `agentAssociation.inputScope` | `Session`, `Intent` | The unit of agent activity that the scorer runs against. Use `Intent` to score each intent in a session individually. | To reference the latest interaction inside a session-scoped scorer, use the [`getLastInteraction`](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-scorer-actions.md#getlastinteraction) invocable action within your prompt template. ### Scorer Definition Reference | Field | Type | Description | | --------------- | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `inputScope` | string | Required. The scope of agent data the scorer's evaluation logic operates on. Valid value: `Session`. | | `scorerType` | string | Required. The scorer's output shape. Valid values: `Predefined`, `OpenEnded`. Use `Predefined` when the scorer returns one of a fixed set of values; use `OpenEnded` for free-form output typed by a Lightning Type. | | `dataType` | string | Required. The data type of the scorer's output. Valid values: `Text`, `Number`, `LightningType`. Use `Text` or `Number` with `scorerType: Predefined`; use `LightningType` with `scorerType: OpenEnded`. | | `lightningType` | string | Required when `dataType` is `LightningType`. The Lightning Type that describes the scorer's output — for example, `lightning__numberType`, `lightning__textType`, or `lightning__booleanType`. | | `semanticType` | string | Optional. Describes how to interpret the scorer's output for reporting. Valid values: `Dimension`, `Measurement`. | | `scorerVersion` | [scorerVersion[]](#scorerversion) | Required. The version configuration for the scorer. Scorers support multiple versions. | ### `scorerVersion` Version numbers must be sequential starting from 1, and each scorer supports a maximum of 100 versions. | Field | Type | Description | | ------------------ | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | | `versionNumber` | integer | Required. The version number. Must be sequential starting from `1`. | | `status` | string | Required. The lifecycle status. Valid values: `Draft`, `Available`, `Archived`. See [Scorer Status](#scorer-status). | | `description` | string | Required. A description of what the scorer evaluates. | | `label` | string | Required. A display label for the scorer version. | | `agentAssociation` | AgentAssociation | Required. Associates the scorer with a specific agent. | | `engine` | [engine[]](#engine) | Required. The evaluation logic for the scorer. | | `outputEnumValue` | [outputEnumValue[]](#outputenumvalue) | Required. One or more mappings that translate engine output values to pass or fail outcomes. | | `specification` | [specification[]](#specification) | Optional. Constraints on the scorer's output values, such as min, max, step, and threshold. | ### `agentAssociation` | Field | Type | Description | | -------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `isActive` | boolean | Required. Whether the scorer is active for the associated agent. Can only be `true` for versions with `Available` status. Only one agent association per scorer can have `isActive` set to `true`. Set to `false` for scorers with `engineType: Manual` — manual scorers are annotated by human reviewers and have no active state. | | `agentApiName` | string | Required. The API name of the agent. The agent must exist in the org. For example, `Copilot_for_Salesforce`. | | `inputScope` | string | Optional. The unit of agent activity that this scorer runs against for the associated agent. Valid values: `Session`, `Intent`. Use `Intent` to score each intent in a session individually. | | `samplingRate` | double | Optional. A value greater than `0` and up to `1.0` that controls the sampling rate. Default is `1.0`. | ### `engine` | Field | Type | Description | | ------------ | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | | `engineType` | string | Required. The type of evaluation engine. Valid values: `PromptTemplate`, `Manual`. Use `Manual` for scorers that accept human-reviewed scores. | | `engineRef` | string | Required when `engineType` is `PromptTemplate`. The API name of the prompt template. Omit for `Manual` scorers. | ### `outputEnumValue` | Field | Type | Description | | ------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `value` | string | Required. The engine output value that maps to this outcome. | | `outcomeType` | string | Optional. The test outcome. Valid values are: `Pass`, `Fail`, `NotApplicable`. Default value is `NotApplicable`. | | `description` | string | Optional. A description of what this output value represents. | | `isFallback` | boolean | Optional. Whether the LLM can emit this value as the scorer's fallback — for example, `Neutral` for a `High`/`Normal`/`Low` scorer. Required for `Predefined` scorers with `dataType: Text`; not applicable to `Predefined` scorers with `dataType: Number`. | | `isSystemFallback` | boolean | Optional. Whether the system uses this value when the prompt template or LLM execution fails. Often set together with `isFallback` on the same value. | ### `specification` | Field | Type | Description | | ----------- | ------ | ------------------------------------------------------------------ | | `max` | double | The maximum valid output value. | | `min` | double | The minimum valid output value. | | `step` | double | The increment between valid output values. | | `threshold` | double | Optional. Output values greater than or equal to `threshold` pass. | ## Scorer Status Each scorer version progresses through a lifecycle controlled by the `status` field. | Status | Description | | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `Draft` | A work in progress. Use `Draft` to edit the scorer's fields freely. A draft version can't run evaluations. | | `Available` | A finalized scorer. For scorers with `engineType: PromptTemplate`, set `agentAssociation.isActive` to `true` to activate it for evaluation. Manual scorers keep `isActive` set to `false` — reviewers post scores directly through the Annotation API. | | `Archived` | A retired version. The Testing API no longer runs evaluations against this version. | Create a scorer version in `Draft` status when you want to iterate on the scorer's configuration before finalizing it. When the scorer is ready for use, promote the version to `Available`. After a version is marked `Available`, its status can't be changed back to `Draft`. ## Example Scorer Definition This example defines a custom scorer that evaluates whether a customer drops off before a conversation resolves. The scorer uses a prompt template to analyze the session and outputs a value of `0` (no drop-off, pass) or `1` (drop-off detected, fail). ```xml Session Number 1 Available Detects whether the customer dropped off before the conversation was resolved. true Copilot_for_Salesforce Session PromptTemplate Drop_Off_Detection_Template true Pass 0 false Fail 1 1 0 1 1 ``` ## Deploy a Custom Scorer To deploy a custom scorer, create a project directory with this structure: ```text my-scorer-project/ ├── package.xml └── aiAgentScorerDefinitions/ └── my_scorer_name.aiAgentScorerDefinition ``` The `package.xml` file specifies the scorer to deploy: ```xml my_scorer_name AiAgentScorerDefinition 66.0 ``` The `members` value must match the filename of your `.aiAgentScorerDefinition` file (without the extension). Deploy the scorer to your org with the Salesforce CLI: ```bash sf project deploy start --metadata-dir my-scorer-project ``` ### Deploy a Scorer with a Prompt Template If your scorer uses the `PromptTemplate` engine type, you can deploy both the template and the scorer together. Add a `genAiPromptTemplates` folder containing your prompt template definition, and add the template to `package.xml`. ```text my-scorer-project/ ├── package.xml ├── genAiPromptTemplates/ │ └── my_prompt_template.genAiPromptTemplate └── aiAgentScorerDefinitions/ └── my_scorer_name.aiAgentScorerDefinition ``` ```xml my_prompt_template GenAiPromptTemplate my_scorer_name AiAgentScorerDefinition 66.0 ``` **note:** In `package.xml`, the `GenAiPromptTemplate` type must appear before `AiAgentScorerDefinition`. Metadata API deploys types in the order that they appear, and the prompt template must exist before the scorer that references it can successfully deploy. ### Retrieve an Existing Scorer To retrieve a scorer definition from your org, use the Salesforce CLI: ```bash sf project retrieve start --metadata AiAgentScorerDefinition:my_scorer_name ``` You can also retrieve a scorer definition by using the same `package.xml` that you used for deployment. ## Update a Custom Scorer To update an existing scorer, modify the `.aiAgentScorerDefinition` file and redeploy. Keep in mind these constraints: - You can add new versions to a scorer, but you can't delete existing versions. - You can edit a version's fields while its `status` is `Draft`. - You can promote a version's `status` from `Draft` to `Available`, or move an `Available` version to `Archived`. After a version is marked `Available`, you can't change its status back to `Draft`. - You can update the `agentAssociation` `isActive` and `samplingRate` values. - The scorer checks the `members` name in `package.xml`. If a scorer with that name already exists, the deployment updates the existing scorer. - Scorers with `engineType: Manual` don't have an active state — always set `agentAssociation.isActive` to `false`. Human reviewers post scores directly through the Annotation API regardless of the association's `isActive` value. ## See Also - [Invocable Actions for Custom Scorers](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-scorer-actions.md) - [Build Tests in Metadata API](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-build-tests.md) - [Add Custom Evaluation Criteria to a Test Case](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-custom-evaluation-criteria.md) - [Metadata API Reference](/docs/ai/agentforce/references/testing-api/testing-metadata-reference.html) - [Deploy and Run Tests in the Command Line](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-cli.md) # Custom Connections Custom connections connect an external web client to an Agentforce agent through the [Agent API](https://developer.salesforce.com/docs/ai/agentforce/agent-api/agent-api.md). You define a metadata-based connection that tells the agent which structured response formats your client supports, and the agent returns JSON that conforms to those schemas so your client can render native UI components like carousels, cards, forms, or pickers. ## When to Use a Custom Connection Consider building a custom connection when you want to: - Host a chat experience in your own infrastructure, outside of Salesforce-managed surfaces. - Render agent responses as native UI components in your client—carousels, cards, forms, pickers, or any other component your design system supports. - Keep full control of the client-side experience while still using Agentforce for reasoning, subagent selection, and action execution. **note:** If an out-of-the-box channel like [Enhanced Chat v2](https://developer.salesforce.com/docs/ai/agentforce/enhanced-chat/get-started-enhanced-chat.md) meets your needs, use that instead. Custom connections are for teams that need to build a channel from the ground up. ## How It Works A custom connection is defined through two metadata types that you deploy to your org: - **`AiSurface`** defines the connection itself, including surface-level instructions and the set of response formats available to the agent. - **`AiResponseFormat`** defines a single structured output format using a JSON schema. The agent uses the format's description and instructions to decide when to apply it, then maps its response into the schema so your client can render the output as a specific UI component. You associate the connection with an agent by adding a `plannerSurfaces` entry to the agent's `GenAiPlannerBundle`. Your client then starts agent sessions through the [Agent API](https://developer.salesforce.com/docs/ai/agentforce/agent-api/agent-api.md), passing `surfaceConfig` in the session initialization request to tell the agent to use your custom connection. ### Response Format Selection When the agent generates a response, it uses this process to decide whether to apply a response format: 1. **Topic and action instructions run first.** The agent processes the topic and action instructions associated with the current conversation turn before evaluating response formats. 2. **Response format selection.** The agent evaluates the `description` and `instructions` on each enabled `AiResponseFormat` and selects at most one format per turn—the one it judges to best fit the current response. The `instructions` on the `AiSurface` provide additional high-level guidance (for example, "don't use formatting for single text-only choices"). 3. **Fallback.** If no response format is selected—or if the agent encounters an error while producing structured output, the agent returns a standard Agent API response with unformatted text. There are no visible logs that provide information on why a response format was not selected. The `sortOrder` value on each `instructions` entry controls the order in which those instructions are fed to the LLM. Lower values are sent first. Ordering influences but does not enforce priority because selection is nondeterministic. **warning:** All instructions on response formats are nondeterministic. The agent uses natural language instructions when choosing which schema to apply, but there is no strict enforcement. The agent may select the wrong format or produce output that doesn't perfectly conform to the JSON schema defined in the `input` field. Build your client-side parsing to handle both well-formed structured responses and plain-text fallback responses. ## Resources - [Set Up a Custom Connection](https://developer.salesforce.com/docs/ai/agentforce/guide/custom-connections-get-started.md) - [Response Format Examples for Custom Connections](https://developer.salesforce.com/docs/ai/agentforce/guide/custom-connections-response-formats.md) - [Troubleshoot Custom Connections](https://developer.salesforce.com/docs/ai/agentforce/guide/custom-connections-troubleshooting.md) - [Agent API Developer Guide](https://developer.salesforce.com/docs/ai/agentforce/agent-api/agent-api.md) # Custom Icons `enum class AgentforceIconType` Enumerates every icon slot in the full-UI chat experience that you can replace, and pairs with `AgentforceIcon` to carry your replacement image(s). Declared in package `com.salesforce.android.agentforcesdk.components.theme`. ## AgentforceIcon ```kotlin class AgentforceIcon( light: Painter, dark: Painter = light, ) ``` Supply a single painter to use in both light and dark mode, or separate `light` and `dark` painters for icons that need different artwork per mode. ## Setting icon overrides Map an `AgentforceIconType` to an `AgentforceIcon` in `AgentforceThemeOverrides`: ```kotlin import com.salesforce.android.agentforcesdk.components.theme.AgentforceIcon import com.salesforce.android.agentforcesdk.components.theme.AgentforceIconType import com.salesforce.android.agentforcesdk.components.theme.AgentforceThemeOverrides val overrides = AgentforceThemeOverrides( icons = mapOf( // Same image for light and dark: AgentforceIconType.ActionSend to AgentforceIcon(mySendPainter), // Separate variants: AgentforceIconType.StatusError to AgentforceIcon(light = myErrorLight, dark = myErrorDark), ) ) ``` ## Members (partial) The enum covers 23 replaceable icons. These are the slots referenced elsewhere in the theming docs: | Member | Covers | | ------------- | ---------------------------------- | | `ActionSend` | The send-message button icon. | | `StatusError` | The inline chat-error status icon. | | `AiAgent` | The agent's avatar icon. | > This is not the complete list. Get the full `AgentforceIconType` enum and each slot's default drawable from the Android team before publishing. ## Tinting Many icons are recolored by the SDK using a color token, so the drawable you supply should usually be a single-color glyph. If you want your icon to render in its own colors instead of being tinted, set the icon's tint color token to `Color.Unspecified` (see [AgentforceColors](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-colors-android.md)). Each `AgentforceIconType` value documents whether it's tinted and which token drives the tint. ## Reading icon overrides at render time ```kotlin val theme = LocalAgentforceTheme.current val icon = theme.getIcon(AgentforceIconType.ActionSend) // null if not overridden — SDK default applies ``` ## See also - [AgentforceThemeManager](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-theme-manager-android.md) — `getIcon(...)`. - [AgentforceColors](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-colors-android.md) — tint tokens and `Color.Unspecified`. - [Display Names](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-display-name-type-android.md) — the equivalent mechanism for customizable strings. # Custom Lightning Type Examples Here are the examples that explain how to override the default user interface to create a customized appearance of responses on the custom agent’s action with custom Lightning types. - [Customizing User Interface Using Custom Lightning Types with Top-Level Editor and Top-Level Renderer Overrides](https://developer.salesforce.com/docs/ai/agentforce/guide/lightning-types-example-full-editor-renderer.md) - [Customizing User Interface Using Custom Lightning Types with Top-Level Collection Renderer Override](https://developer.salesforce.com/docs/ai/agentforce/guide/lightning-types-example-collection-renderer.md) # Custom Lightning Types on Mobile with the Agentforce Mobile SDK Use Custom Lightning Types (CLTs) to control how structured agent action data appears in Agentforce on mobile. In apps that integrate the Agentforce Mobile SDK, you can route CLT output and input through native UI (SwiftUI or Jetpack Compose) by implementing a view provider and using the `AFMobileCustom/` prefix in your CLT metadata. > For LWC-based CLT overrides in the Salesforce mobile app, see [Custom Lightning Types in the Salesforce Mobile App](https://help.salesforce.com/s/articleView?id=xcloud.salesforce_app_clt_mobile.htm&type=5) in Salesforce Help. ## Configure CLT metadata for mobile Agentforce CLT UI configuration is organized by channel, similar to desktop. For Agentforce on mobile, add a `lightningMobileGenAi` folder next to your existing channel folders (for example `lightningDesktopGenAi`). You can configure desktop and mobile independently. Output (renderer) — example layout for a type named `flightResponse`: ``` +--lightningTypes +--flightResponse +--schema.json +--lightningDesktopGenAi +--renderer.json +--lightningMobileGenAi +--renderer.json ``` Input (editor) — example layout for a type named `flightFilter`: ``` +--lightningTypes +--flightFilter +--schema.json +--lightningDesktopGenAi +--editor.json +--lightningMobileGenAi +--editor.json ``` ### Renderer override for native mobile (output) In `lightningMobileGenAi/renderer.json`, use the top-level `$` override and set `definition` to an `AFMobileCustom/…` identifier that your app handles. ```json { "renderer": { "componentOverrides": { "$": { "definition": "AFMobileCustom/FlightDetails" } } } } ``` ### Map schema fields to native properties If your native view expects different property names than the schema, use `attributes` (same idea as desktop channel overrides): ```json { "renderer": { "componentOverrides": { "$": { "definition": "AFMobileCustom/FlightDetails", "attributes": { "flightCost": "{!$attrs.price}", "discountPercentage": "{!$attrs.discountPercentage}" } } } } } ``` ### Editor override for native mobile (input) In `lightningMobileGenAi/editor.json`: ```json { "editor": { "componentOverrides": { "$": { "definition": "AFMobileCustom/FlightFilter" } } } } ``` The editor is shown when the type is used as input in the mobile conversation; implementation uses the same view provider pattern as renderers. ## Implement native UI on iOS 1. Conform to `AgentforceViewProviding`. 2. Return `true` from `canHandle(type:)` for each `AFMobileCustom/…` definition you support. 3. Return the appropriate SwiftUI view from `view(for:data:)`. ```swift import SwiftUI import AgentforceSDK class FlightDetailsViewProvider: AgentforceViewProviding { func canHandle(type: String) -> Bool { type == "AFMobileCustom/FlightDetails" } @MainActor func view(for type: String, data: [String: Any]) -> AnyView { switch type { case "AFMobileCustom/FlightDetails": return AnyView(FlightDetailsView(data: data)) default: return AnyView(EmptyView()) } } } ``` Register the provider when you create `AgentforceClient`. Pass `viewProvider` along with `credentialProvider`, `mode`, and other required parameters for your agent type (employee, service, or full configuration), as described in [Integrate Agentforce SDK](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/ios/agentforce-mobile-sdk-ios-integration.md). ```swift let client = AgentforceClient( credentialProvider: credentialProvider, mode: .employeeAgent(config), viewProvider: FlightDetailsViewProvider(), themeManager: AgentforceDefaultThemeManager() ) ``` For more on client setup, see [iOS configuration](/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/configuration-overview-ios.html) in the Agentforce Mobile SDK reference (including AgentforceClient and AgentforceConfiguration). ## Implement native UI on Android 1. Implement `AgentforceViewProvider`. 2. Return `true` from `canHandle(definition:)` for each `AFMobileCustom/…` definition. 3. In `GetView`, read payload data (for example from `AgentforceComponent` / `view.properties`) and compose your UI. ```kotlin class FlightDetailsViewProvider : AgentforceViewProvider { override fun canHandle(definition: String): Boolean { return definition == "AFMobileCustom/FlightDetails" } @Composable override fun GetView(modifier: Modifier, view: AgentforceComponent) { val flightData = view.properties["value"] FlightDetailsCard(modifier = modifier, data = flightData) } } ``` Register the provider on `AgentforceConfiguration`: ```kotlin val config = AgentforceConfiguration.builder( authCredentialProvider = /* your provider */ ) .setViewProvider(FlightDetailsViewProvider()) // ... other configuration .build() ``` See [Integrate Agentforce SDK](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/android/agentforce-mobile-sdk-android-integration.md) and [Android configuration](/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/configuration-overview-android.html) in the Agentforce Mobile SDK reference for `setViewProvider` and related builder options. ## Handle multiple definitions in one provider You can implement `canHandle` / `GetView` (or `view(for:data:)` on iOS) for several `AFMobileCustom/…` strings in a single class. iOS (SwiftUI) ```swift class MyAppViewProvider: AgentforceViewProviding { func canHandle(type: String) -> Bool { type == "AFMobileCustom/FlightDetails" || type == "AFMobileCustom/FlightFilter" } @MainActor func view(for type: String, data: [String: Any]) -> AnyView { switch type { case "AFMobileCustom/FlightDetails": return AnyView(FlightDetailsView(data: data)) case "AFMobileCustom/FlightFilter": return AnyView(FlightFilterView(data: data)) default: return AnyView(EmptyView()) } } } ``` Android (Jetpack Compose) ```kotlin class MyAppViewProvider : AgentforceViewProvider { override fun canHandle(definition: String): Boolean { return definition in listOf( "AFMobileCustom/FlightDetails", "AFMobileCustom/FlightFilter" ) } @Composable override fun GetView(modifier: Modifier, view: AgentforceComponent) { when (view.definition) { "AFMobileCustom/FlightDetails" -> FlightDetailsCard(modifier = modifier, data = view.properties["value"]) "AFMobileCustom/FlightFilter" -> FlightFilterEditor(modifier = modifier, data = view.properties["value"]) else -> { /* no-op */ } } } } ``` ## React Native apps Custom Lightning Types are supported in apps that use the Agentforce React Native SDK when you render them with native-style overrides: CLT metadata that uses the `AFMobileCustom/…` prefix, implemented through the native iOS and Android SDKs behind the bridge. 1. Enable `enableCustomViewProvider` in feature flags. 2. Register a View Provider delegate and map each `AFMobileCustom/…` definition string to a React Native component (registered with `AppRegistry`), the same way you map other SDK component definitions. See [Delegates](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/react-native/agentforce-mobile-sdk-react-native-delegates.md). > **Tip:** Before mapping a definition in your `componentMap`, log the actual `definition` prop that the native SDK sends to the rendered component. The native `canHandle()` lookup is an exact string match — any mismatch (casing, extra whitespace, typo) silently renders nothing. Not supported in React Native today — using Lightning web components (LWC) as the CLT renderer or editor inside the bridge, and using React web components inside CLT. Those UI paths are separate from the native-override flow above. For details and caveats, see [React Native SDK Limitations](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/react-native/agentforce-mobile-sdk-react-native-limitations.md#custom-lightning-types-lwc-and-react-web-ui). ## See also - [Message Response Formatting](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-message-formatting.md) (Markdown responses and HTML in the `lightning__richText` component) - [Custom Lightning Types in the Salesforce Mobile App](https://help.salesforce.com/s/articleView?id=xcloud.salesforce_app_clt_mobile.htm&type=5) (LWC overrides in the Salesforce mobile app) - [Customize the Agent Action UI with Lightning Types](/docs/ai/agentforce/guide/lightning-types.html) - [Customizing User Interface Using Custom Lightning Types with Top-Level Editor and Top-Level Renderer Overrides](/docs/ai/agentforce/guide/lightning-types-example-full-editor-renderer.html) - [Integrate Agentforce SDK (iOS)](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/ios/agentforce-mobile-sdk-ios-integration.md) - [Integrate Agentforce SDK (Android)](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/android/agentforce-mobile-sdk-android-integration.md) # Customize an Agent That Doesn't Use Agent Script (Legacy) **warning:** This section describes the process of customizing agents that were created without using Agent Script as their blueprint. We don't recommend that you use this legacy workflow anymore to create an agent. Instead, we recommend that you author agents that use the Agent Script language, which is the next-gen way of creating agents. To customize the agent, you then simply modify its Agent Script file. See [Author an Agent with Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-nga-author-agent.md) and [Code Your Agent Using Its Script File](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-nga-script.md). After you create a basic agent, customize it so that it does what you want. As always, you can use low-code builders or pro-code developer tools to develop the different parts of the agent. ## Determine What Customization You Need and Which Tool To Use The main way you customize an agent is to add more subagents and actions. Sometimes you can use an existing subagent or action from your development org’s reference library. But at other times, to meet your specific business needs, you must create a custom subagent or action. This table lists the various customizations you can make to your agent, the best tool to use, and where to get more information. | Customization Task | Best Tool | Related Documentation | | :--------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Add a standard action from the reference library to an existing subagent. | Use Agentforce Builder. |
  • [Add an Action to a Subagent](https://help.salesforce.com/s/articleView?id=ai.copilot_actions_add.htm&type=5)
  • [Standard Agent Action Reference](https://help.salesforce.com/s/articleView?id=ai.copilot_actions_ref.htm&type=5)
| | Create a custom action based on an Apex class, and then add it to an existing subagent. | To help you code the Apex class, use VS Code with Agentforce Vibes Extension. To add it to a subagent, use Agentforce Builder. |
  • [Build Custom Actions using Apex REST](https://developer.salesforce.com/docs/ai/agentforce/agent-apex/agent-apex.md).
  • [Apex Development with VS Code Salesforce Extensions](https://developer.salesforce.com/docs/platform/sfvscode-extensions/guide/apex-overview.html)
  • [Agentforce Vibes Extension](https://developer.salesforce.com/docs/platform/einstein-for-devs/guide/einstein-overview.html)
  • [Create a Custom Action for Agents](https://help.salesforce.com/s/articleView?id=ai.copilot_actions_custom_create_scratch.htm&type=5)
  • [Add an Action to a Subagent](https://help.salesforce.com/s/articleView?id=ai.copilot_actions_add.htm&type=5)
| | Create a custom action based on an autolaunched flow, and then add it to an existing subagent. | To create the flow, use Flow Builder. To add it to a subagent, use Agentforce Builder. |
  • [About Flows and Flow Builder](https://help.salesforce.com/s/articleView?id=platform.automate_flow_about.htm&type=5)
  • [Create a Custom Action for Agents](https://help.salesforce.com/s/articleView?id=ai.copilot_actions_custom_create_scratch.htm&type=5)
  • [Add an Action to a Subagent](https://help.salesforce.com/s/articleView?id=ai.copilot_actions_add.htm&type=5)
| | Create a custom action based on a prompt template, and then add it to an existing subagent. | To create the prompt template, use Prompt Builder. To add it to a subagent, use Agentforce Builder. |
  • [Prompt Builder](https://help.salesforce.com/s/articleView?id=ai.prompt_builder_about.htm&type=5)
  • [Create a Custom Action for Agents](https://help.salesforce.com/s/articleView?id=ai.copilot_actions_custom_create_scratch.htm&type=5)
  • [Add an Action to a Subagent](https://help.salesforce.com/s/articleView?id=ai.copilot_actions_add.htm&type=5)
| | Create a custom action based on an external service and then add it to an existing subagent. | To create the external service, use Setup in your org. To add it to a subagent, use Agentforce Builder. |
  • [Use Agentforce to Invoke External Service Actions](https://help.salesforce.com/s/articleView?id=platform.external_services_custom_agent_actions.htm&type=5)
  • [Create a Custom Action for Agents](https://help.salesforce.com/s/articleView?id=ai.copilot_actions_custom_create_scratch.htm&type=5)
  • [Add an Action to a Subagent](https://help.salesforce.com/s/articleView?id=ai.copilot_actions_add.htm&type=5)
| | Add a subagent from the asset library to your agent. | Use Agentforce Builder. |
  • [Add a Subagent from the Asset Library](https://help.salesforce.com/s/articleView?id=ai.copilot_topics_add_standard.htm&type=5)
  • [Standard Agent Subagent Reference](https://help.salesforce.com/s/articleView?id=ai.copilot_topics_ref.htm&type=5)
| | Create a custom subagent and add it to your agent. | Use Agentforce Builder. |
  • [Create a Custom Subagent](https://help.salesforce.com/s/articleView?id=ai.copilot_topics_add_custom.htm&type=5)
| | Update the agent settings, such as system messages, language settings, and agent versions. |
  • (low-code) Use Agentforce Builder.
  • (pro-code) To edit the agent's metadata directly in your local Salesforce DX project, use VS Code.
|
  • [Set Up Your Agent (Agentforce Builder)](https://help.salesforce.com/s/articleView?id=ai.agent_parent_setup.htm&type=5)
  • [Agentforce Metadata Types](/docs/ai/agentforce/references/agents-metadata-tooling/agents-metadatav67.html)
| # Customize the Agent Action UI with Lightning Types Enhance the chat response experience by creating custom Lightning types. Use these types to override the default user interface with your own Lightning web components to create a branded, interactive experience. You can override the default UI only for agent actions that use Apex classes as input or output. For example, here’s one way that you can enhance the agent action output UI with custom Lightning types. | The default UI for output in an agent action | The customized UI for output in an agent action | | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ![Agent's response to a flight details request, with no labels, a cluttered and unappealing layout, and no Book Now button.](https://developer.salesforce.com/media/lightning-types-images/UI-Comparision-Output1.png '{"class": "image-sm image-framed"}') | ![Agent's response to a flight details request, featuring clear labels, an appealing layout, a highlighted discount, and a prominent Book Now button.](https://developer.salesforce.com/media/lightning-types-images/UI-Comparision-Output2.png '{"class": "image-sm image-framed"}') | **See Also** - [Examples of Custom Lightning Types](https://developer.salesforce.com/docs/ai/agentforce/guide/lightning-types-examples.md) # Customize the Agent Test Spec **warning:** This section describes the legacy process for testing Agentforce agents, or the pro-code equivalent to using the [Legacy Agentforce Testing Center in Setup](https://help.salesforce.com/s/articleView?id=ai.agent_testing_center_setup_tests.htm&type=5). It doesn't apply to the new agent testing process, or the pro-code equivalent to the [New Testing Center in Agentforce Studio (Beta)](https://help.salesforce.com/s/articleView?id=ai.agent_studio_testing_center_setup_tests.htm&type=5). That documentation will be released soon. Running the `agent generate test-spec` command results in a good agent test spec. But there are other items you can add to the file to create even better tests. Because the agent test spec file is in YAML format, it's easy to update manually. ## Test Service Agent Context Variables Service agents can connect to customer channels. Specifically, you can configure your Service agent to route conversations to it with enhanced messaging channels. See [Connect a Service Agent to Messaging](https://help.salesforce.com/s/articleView?id=ai.service_agent_messaging.htm&type=5). You can also personalize your Service agent conversations with context variables. Context variables let your agent use record fields of the Messaging Session standard objects as action inputs. See [Use Context Variables in Service Agent Conversations](https://help.salesforce.com/s/articleView?id=ai.service_agent_context_variables.htm&type=5). If you've configured your Service agent with context variables, you can test how they work at the same time you test your agent. Do this by adding a `contextVariables:` section to your test cases in the agent test spec. For each context variable you want to test, add a `name`|`value` pair. The `name` property is the API name of the context variable and `value` is a specific value you want to test. For example, let's say that you added the EndUserLanguage context variable to your Service agent. This variable specifies the preferred language of the user participating in the messaging session. To run a test case as if the user were talking in Spanish, manually update your YAML agent test spec like this. ```yaml testCases: - utterance: Are there any resort experiences that match my interests today? expectedTopic: Experience_Management expectedActions: [] expectedOutcome: The agent should politely ask for the guest's email address AND membership number. customEvaluations: [] conversationHistory: [] contextVariables: - name: EndUserLanguage value: Spanish ``` To find the API name of a context variable, open your agent in your development org's Agent Builder UI and go to the Context tab. ![Agent Builder showing the Context tab and EndUserLanguage variable highlighted.](https://developer.salesforce.com/media/dx-context-variables.png '{"class": "image-sm"}') Context variable API names correspond to field names of the [MessagingSession](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_messagingsession.htm) standard object. ## Use Metrics to Assess Agent Responses When you run `agent generate test-spec`, the command automatically adds out-of-the-box metrics in a `metrics:` section for each test case in the generated spec YAML file. For example: ```yaml testCases: - utterance: Are there any resort experiences that match my interests today? expectedTopic: Experience_Management expectedActions: [] expectedOutcome: The agent should politely ask for the guest's email address AND membership number. customEvaluations: [] conversationHistory: [] metrics: - coherence - completeness - conciseness - output_latency_milliseconds ``` Use these metrics to assess the quality and latency of agent responses during testing. Including the metric name in the test spec enables the metric information in the test result. Here's what the metrics measure: - **Coherence** - Measures whether the response is easy to understand and has no grammatical errors. - **Completeness** - Measures whether the response includes all the essential information. - **Conciseness** - Measures whether the response is brief but comprehensive. Shorter is better. - **Latency** - Returns the latency in milliseconds from sending a request until a response is received. After you run an agent test that has these metrics in the test YAML file, you get a Metrics section in the test case output similar to this: ```text ❯ METRICS (Value/Threshold) ──────────────────────────────────────────────────────────────────────── ❌ : COMPLETENESS (1/0.6) : The answer does not provide any weather information, which is the main request. It only mentions a technical issue and suggests checking a weather app or website, which does not fully address the user's query. ✅ : COHERENCE (4/0.6) : The answer is easy to understand, free of significant grammar errors, and flows well when read by itself. ✅ : CONCISENESS (5/0.6) ⏱️ : OUTPUT LATENCY (3564ms) ``` See [Use Test Results to Improve Your Agent](https://developer.salesforce.com/docs/ai/agentforce/testing-api/testing-api-use-results.md) for information on the returned scores for these metrics. If you don't want to include these metrics in an agent test run, simply delete the specific metric, or the entire `metrics:` section, from the test case in the spec YAML file. ## Add Custom Evaluation Criteria to an Agent Test Spec Custom evaluations test an agent response for specific strings or numbers. If you opt to add one or more custom evaluations to an agent test case when you run `agent generate test-spec`, you're prompted for the following information: - **Label**: A descriptive name of the custom evaluation. - **JSONPath expression**: Enables you to automatically point to the data you want to test. See [Construct the JSONPath Expression](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-test-customize.md#construct-the-jsonpath-expression) for tips. - **Comparison operator**: The operator used to compare the expected and actual values returned from the test. Examples are equals, greater than or equal, and so on. - **Expected value**: The value you expect after the evaluation is tested. After you enter values, the agent test spec YAML file includes a `customEvaluations` section like this: ``` customEvaluations: - label: Check for correct date name: string_comparison parameters: - name: operator value: equals isReference: false - name: actual value: $.generatedData.invokedActions[*][?(@.function.name == 'Check_Weather')].function.input.dateToCheck isReference: true - name: expected value: "2025-09-12" isReference: false ``` The `agent generate test-spec` command uses the Agentforce Testing API under the covers, so for more information, see [Add Custom Evaluation Criteria to a Test Case](https://developer.salesforce.com/docs/ai/agentforce/testing-api/testing-api-custom-evaluation-criteria.md#get-started-with-custom-evaluation-criteria). ### Construct the JSONPath Expression To construct the JSONPath expression that tests the actual result of a custom evaluation, you need the generated JSON data from an invoked action. To get this information, first [run the agent test](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-test-run.md) without any custom evaluations and specify that you want to see the generated JSON. If you use the `agent test run` CLI command to run an agent test, specify the `--verbose` flag to show the generated JSON data in the test results output. For example: ```bash sf agent test run --api-name Guest_Experience_Agent_Test --verbose ``` The test results output includes a section called **Generated Data**, which includes information about any invoked actions in the agent test run. This sample JSON data shows information about the invoked action (function) called `Check_Weather`: ``` Generated Data ┌───────────────────────────────────────┐ │ Data │ ├───────────────────────────────────────┤ │ [ │ │ [ │ │ { │ │ "function": { │ │ "name": "Check_Weather", │ │ "input": { │ │ "dateToCheck": "2025-09-12" │ │ }, │ │ "output": {} │ │ }, │ │ "executionLatency": 804 │ │ } │ │ ] │ │ ] │ └───────────────────────────────────────┘ ``` If you're using the VS Code Testing Panel to run agent tests, be sure the **Generated Data Output** box is checked; the JSON data is displayed in the **ACTION: INVOCATION** section of the test results. ![VS Code testing panel showing the checked generated data output box and the sample output.](https://developer.salesforce.com/media/dx-generated-data.png) Now that you have the generated JSON data, you can build the required JSONPath expression. This sample JSONPath expression finds the value of the inputted date to the `Check_Weather` function (agent action): ``` $.generatedData.invokedActions[*][?(@.function.name == 'Check_Weather')].function.input.dateToCheck ``` See [Dynamically Reference Generated Data](https://developer.salesforce.com/docs/ai/agentforce/testing-api/testing-api-custom-evaluation-criteria.md#dynamically-reference-generated-data) for more information about constructing a JSONPath expression. ## Add Conversation History to Enhance the Test Context Adding the conversation history to an agent test adds additional context that enables multi-turn testing. Instead of testing single-shot utterance-response pairs, you can now test utterances within the context of a conversation. Including conversation history in an agent test is easy. When you first run `agent generate test-spec`, the command asks if you want to add conversation history to the generated YAML file. If you answer `Y`, the command adds a `conversationHistory` section with a boilerplate conversation, like this: ```yaml testCases: - utterance: Are there any resort experiences that match my interests today? expectedTopic: Experience_Management expectedActions: [] expectedOutcome: The agent should politely ask for the guest's email address AND membership number. customEvaluations: [] conversationHistory: - role: user message: example user message - role: agent message: example agent message topic: Example_agent_topic ``` You can also manually add the `conversationHistory` section to an existing agent test spec YAML file if it doesn't already have one. Then add `role`-`message` pairs that mimic a conversation leading up to the actual agent test. For the agent message (`role: agent`), you must also include the subagent that the agent used to generate a response. This example of a test for a retail agent shows how to add a conversation history in which the user provides an order ID: ```yaml testCases: - utterance: When will my purchase arrive? expectedTopic: Look_Up_Order expectedActions: [Predict_Arrival_Date] expectedOutcome: The agent should tell the customer when their purchase will arrive. customEvaluations: [] conversationHistory: - role: user message: I purchased an item last week but it hasn't arrived yet. - role: agent message: What is your order ID? topic: Ask_for_Order_ID - role: user message: It's 123456. - role: agent message: You ordered a Wacky Cat Bobblehead, right? Great choice. topic: Look_Up_Order ``` # Data Masking with Models API The Einstein Trust Layer identifies and masks selected personally identifiable information (PII) and payment card industry (PCI) data in the prompts before sending them to the large language model (LLM). Data masking prevents your sensitive data from exposure to the LLM and keeps your sensitive CRM data safely stored inside Salesforce. ## Prerequisites To ensure that sensitive data is masked, verify that your desired language and locale is supported, and then follow the admin instructions for setting up data masking. See [Einstein Trust Layer Region and Language Support](https://help.salesforce.com/s/articleView?id=ai.generative_ai_trust_lang_region.htm) and [Large Language Model Data Masking](https://help.salesforce.com/s/articleView?id=ai.generative_ai_mask_data.htm) in _Salesforce Help_. After you verify that your locale is supported and that data masking is turned on, specify the correct locale in your API request. See [Specify Languages and Locales with Models API](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api-languages-and-locales.md). ## How It Works Data masking involves replacing each value that’s detected with placeholder text based on what it represents. Then, the LLM can maintain the context of the prompt to generate a relevant response. After the LLM returns a response, the Einstein Trust Layer demasks the data that was originally masked. The response that you see has the actual data. You can track data masking and view the masked data by using the audit trail. Audit trail is stored in Data 360. There’s no programmatic way to handle masked data from the Models API. **note:** Although our detection models have shown to be effective during internal testing, it’s important to note that no model can guarantee 100% accuracy. In addition, cross-region and multi-country use cases can affect the ability to detect specific data patterns. With trust as our priority, we’re dedicated to the ongoing evaluation and refinement of our models. ## Context Window Although some of the [supported models](https://developer.salesforce.com/docs/ai/agentforce/supported-models.md#model-criteria) have extended context windows, all models are currently limited to a context size of 65,536 tokens when data masking is turned on in the Einstein Trust Layer. To turn off data masking and use the full context window, see [Set Up Einstein Trust Layer](https://help.salesforce.com/s/articleView?id=ai.generative_ai_trust_setup.htm) in Salesforce Help. ## See Also - _Salesforce Help_: [Einstein Trust Layer Region and Language Support](https://help.salesforce.com/s/articleView?id=ai.generative_ai_trust_lang_region.htm) - _Salesforce Help_: [Large Language Model Data Masking](https://help.salesforce.com/s/articleView?id=ai.generative_ai_mask_data.htm) # Define Agent Metadata (v67 and Earlier) Create a manifest to define the metadata you want to retrieve. You can copy and edit the default manifest that was created in your project at `manifest/package.xml`. ## Understand Agent and Legacy Agent Metadata (v67 and Earlier) - Draft (uncommitted) agents and agent versions are represented by `AiAuthoringBundle`, **not** `Bot` or `BotVersion`. You **can** edit a draft agent. - Committed agents and agent versions are represented by `AiAuthoringBundle`, plus `Bot` and `BotVersion`. You **can't** edit a committed agent. Instead, create and edit a new version. - Legacy agents don't have a commit stage, and are represented by `Bot` and `BotVersion` (not `AiAuthoringBundle`). You can edit and overwrite an active legacy agent. | Agent Type | Metadata Representation | Editable | | :-------------- | :--------------------------------------- | :------------------------------------------------------ | | Draft Agent | `AiAuthoringBundle` | Yes | | Committed Agent | `AiAuthoringBundle`, `Bot`, `BotVersion` | No | | Legacy Agent | `Bot` and `BotVersion` | Inactive versions are editable, active versions are not | See [Agentforce Metadata Types](/docs/ai/agentforce/references/agents-metadata-tooling/agents-metadatav67.html). ## Example package.xml Manifest Files Use these examples to get started: - Replace the version number (for example, `65.0`) with your required metadata version. Your project's sample `package.xml` manifest contains the most recent version number. - Add any other metadata types that your agent needs, such as Data 360 dependencies. | Example Manifest | Description | Notes | | --------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Manifest Defining All Agents (v67 and Earlier)](https://developer.salesforce.com/docs/ai/agentforce/guide/package-allagents67.md) | Defines metadata for all agents, including legacy agents. Includes metadata for all flows, prompt templates, and Apex classes in the org. | Replace the `*` wildcard with the API names of the ApexClass, Flows, and GenAiPromptTemplates that your agents use. Using wildcards for these types can pull excessive data, leading to very long deployments or timeouts. | | [Manifest Defining a Single Agent Version (v67 and Earlier)](https://developer.salesforce.com/docs/ai/agentforce/guide/package-singleagent67.md) | Defines a single version of an agent, plus the flows, prompt templates, and Apex class types that the agent version uses. | Before deploying a single agent version into an org (using `BotVersion`), you must have deployed the full agent to the org. Deploying the agent before deploying a specific version ensures that all required metadata and artifacts are created in the target org. | | [Manifest for Different Bot/AiAuthoringBundle Versions (v67 and Earlier)](https://developer.salesforce.com/docs/ai/agentforce/guide/package-single-mismatch67.md) | Defines a single agent version when the `AiAuthoringBundle` version doesn't match the `Bot`/`BotVersion` version. | This difference can happen when you save more versions than you commit. See [(Optional) - Update Your Manifest for Different Bot/AiAuthoringBundle Versions()](#optional---update-your-manifest-for-different-botaiauthoringbundle-versions). | ### Update Your Manifest To define a single agent version, make these changes to your manifest. 1. Instead of `Bot`, which is the top-level representation of an agent, use `BotVersion`, which represents the configuration for a specific agent version. Include the agent version's name and version number. For example: ```xml NGA_Service_Agent.v2 BotVersion ``` 2. Instead of using the agent's name to specify `AiAuthoringBundle` and `GenAiPlannerBundle`, use the agent's versioned name. For example: ```xml NGA_Service_Agent_2 AiAuthoringBundle AgentforceServiceAgent_v2 GenAiPlannerBundle ``` (Optional) - Update Your Manifest for Different Bot/AiAuthoringBundle Versions Use these steps to specify the correct versions for your agent's metadata. ## (Optional) - Update Your Manifest for Different Bot/AiAuthoringBundle Versions Use these steps to specify the correct versions for your agent’s metadata. ### What are mismatched `Bot`/`AiAuthoringBundle` versions? When you save an agent version, Agentforce creates `AiAuthoringBundle` metadata. When you commit an agent version, Agentforce creates Bot/BotVersion metadata. If you save more versions than you commit, the version of your `AiAuthoringBundle` won't match the version of your Bot/BotVersion. For example, this agent has 11 versions of an agent and 7 committed versions. Therefore, the agent's metadata contains 11 versions of `AiAuthoringBundle` and 7 versions of `Bot` and `BotVersion`. You'll need to specify the correct version numbers to match the correct `AiAuthoringBundle` to the correct `Bot` and `BotVersion`. ![Diagram showing draft AiAuthoringBundle versions that don't match committed Bot/BotVersion numbers](https://developer.salesforce.com/media/agent-script/agent-dx-draft-versions.png '{"class": "image-sm"}') To find the matching `Bot` version, open the AiAuthoringBundle folder for your desired version. In the agent version's `bundle-meta.xml` file, the `target` metadata shows the version to use for the `GenAiPlannerBundle` and `BotVersion`. For example, version 9 of the agent "TestAgentFromSource" uses version 7 of `GenAiPlannerBundle` and `BotVersion`. ![Selecting the target for the agent version](https://developer.salesforce.com/media/agent-script/agent-dx-target.png) Use these versions to specify your manifest, for example [Manifest for Different Bot/AiAuthoringBundle Versions (v67 and Earlier)](https://developer.salesforce.com/docs/ai/agentforce/guide/package-single-mismatch67.md) # Delegates in React Native Learn how to use delegates to receive events and customize behavior from the Agentforce SDK in your React Native application. ## Overview Delegates allow your JavaScript code to receive events and override behavior from the native Agentforce SDK. The bridge supports three delegate types: | Delegate | Purpose | Direction | | ------------- | ------------------------------------------------------ | ---------------------------------------------------- | | Logger | Receive SDK log messages | Native → JS | | Navigation | Handle navigation requests from the agent | Native → JS | | View Provider | Override native SDK views with React Native components | JS → Native (registration) + Native → JS (rendering) | All delegates use a `NativeEventEmitter` on the JS side to receive events from the native layer. ### Why Register Before configure()? The recommended order is to register delegates **before** calling `configure()`. Here's why: - **Logger**: The SDK may emit log messages during initialization. If registered after `configure()`, those early messages are lost. - **Navigation**: The navigation bridge is passed to `AgentforceConfiguration` during `configure()`. Registering afterward still works because the bridge checks dynamically, but registering before is cleaner. - **View Provider**: Can be registered before or after `configure()` without issue. The native view provider checks the component map dynamically. ## Logger Delegate The Logger delegate forwards log messages from the native Agentforce SDK to your JavaScript code. This is useful for debugging, analytics, and monitoring. ### Setup ```tsx import { AgentforceService } from "@salesforce/react-native-agentforce"; AgentforceService.setLoggerDelegate({ onLog(level, message, error) { const prefix = `[Agentforce ${level.toUpperCase()}]`; if (error) { console.log(`${prefix} ${message} | Error: ${error}`); } else { console.log(`${prefix} ${message}`); } }, }); ``` ### Parameters | Parameter | Type | Description | | --------- | ---------------------------------------- | ---------------------------------------------------------- | | `level` | `'error' \| 'warn' \| 'info' \| 'debug'` | The severity level of the log message. | | `message` | `string` | The log message from the SDK. | | `error` | `string` (optional) | Stringified exception, present only for error/warn levels. | ### Clear the Delegate ```tsx AgentforceService.clearLoggerDelegate(); ``` ### Platform Differences | Platform | Log Levels Emitted | | -------- | -------------------------------- | | iOS | `error`, `warn`, `info`, `debug` | | Android | `error`, `warn`, `info` | iOS emits the `debug` level; Android doesn't. Plan your log filtering accordingly. ### Example: Analytics Forwarding ```tsx AgentforceService.setLoggerDelegate({ onLog(level, message, error) { if (level === "error") { analytics.track("Agentforce Error", { message, error: error || undefined, }); } }, }); ``` ## Navigation Delegate The Navigation delegate lets your app handle navigation requests from the Agentforce SDK. When the agent presents a link, record reference, or other navigable element that the user taps, the SDK emits a navigation event. ### Setup ```tsx import { Linking } from "react-native"; import { AgentforceService } from "@salesforce/react-native-agentforce"; AgentforceService.setNavigationDelegate({ onNavigate(request) { switch (request.type) { case "link": if (request.uri) { Linking.openURL(request.uri as string); } break; case "record": // Navigate to a record detail screen in your app navigation.navigate("RecordDetail", { recordId: request.recordId, objectType: request.objectType, }); break; case "quickAction": console.log(`Quick action requested: ${request.actionName}`); break; case "objectHome": navigation.navigate("ObjectList", { objectType: request.objectType, }); break; default: console.log("Unhandled navigation:", JSON.stringify(request)); } }, }); ``` ### Navigation Request Types | Type | Description | Fields | | --------------- | -------------------------------------- | ------------------------------------------ | | `record` | Navigate to a Salesforce record | `recordId`, `objectType`, `pageReference?` | | `link` | Open an external or internal URL | `uri`, `pageReference?` | | `quickAction` | Execute a Salesforce quick action | `actionName`, `recordId?`, `objectType?` | | `pageReference` | Navigate to a Lightning page reference | `pageReference` | | `objectHome` | Navigate to an object's home/list page | `objectType`, `pageReference?` | | `app` | Navigate to an app or external package | `packageName`, `uri?` | | `unknown` | Catch-all for unrecognized types | `raw` | ### Clear the Delegate ```tsx AgentforceService.clearNavigationDelegate(); ``` ## View Provider Delegate The View Provider delegate allows you to replace native SDK output views with custom React Native components. When the SDK renders a component type that matches your registered map, your React Native component is rendered instead. ### Setup There are two parts to registering a custom view: **Part 1: Register the React Native component with AppRegistry** ```tsx import { AppRegistry } from "react-native"; import { ViewProviderComponentData } from "@salesforce/react-native-agentforce"; function CustomRichTextView({ componentData }: { componentData: ViewProviderComponentData }) { const text = componentData.properties.text as string; return ( {text} ); } // Register it with AppRegistry AppRegistry.registerComponent("CustomRichTextView", () => CustomRichTextView); ``` **Part 2: Register the component map with the bridge** ```tsx await AgentforceService.setViewProviderDelegate({ componentMap: { "copilot/richText": "CustomRichTextView", "copilot/markdown": "CustomMarkdownView", }, }); ``` The keys are SDK component definition strings. The values are the names you registered with `AppRegistry.registerComponent()`. ### Complete Custom View Provider Example This example shows a full custom view component that handles all properties and sub-components: ```tsx // CustomAgentforceView.tsx import React from "react"; import { View, Text, ScrollView, StyleSheet } from "react-native"; import type { ViewProviderComponentData } from "@salesforce/react-native-agentforce"; interface Props { componentData: ViewProviderComponentData; } function CustomAgentforceView({ componentData }: Props) { const { definition, name, properties, subComponents } = componentData; return ( {definition} {name && {name}} {Object.entries(properties).map(([key, value]) => ( {key}: {typeof value === "object" ? JSON.stringify(value) : String(value)} ))} {subComponents && subComponents.length > 0 && ( Sub-Components ({subComponents.length}) {subComponents.map((sub, index) => ( {sub.definition} {JSON.stringify(sub.properties, null, 2)} ))} )} ); } const styles = StyleSheet.create({ container: { margin: 8, padding: 12, backgroundColor: "#f8f9fa", borderRadius: 8, borderWidth: 1, borderColor: "#dee2e6", }, header: { marginBottom: 8 }, defLabel: { fontSize: 14, fontWeight: "bold", color: "#0176D3" }, nameLabel: { fontSize: 12, color: "#666", marginTop: 2 }, propsContainer: { maxHeight: 200 }, propRow: { flexDirection: "row", marginBottom: 4 }, propKey: { fontWeight: "600", marginRight: 8, color: "#333" }, propValue: { flex: 1, color: "#555" }, subSection: { marginTop: 12, paddingTop: 8, borderTopWidth: 1, borderTopColor: "#eee" }, subTitle: { fontWeight: "bold", marginBottom: 4 }, subItem: { marginLeft: 12, marginBottom: 8 }, subDef: { fontWeight: "600", fontSize: 12 }, subProps: { fontFamily: "monospace", fontSize: 10, color: "#666" }, }); export default CustomAgentforceView; ``` **Register the component and mapping in your App.tsx:** ```tsx import { AppRegistry } from "react-native"; import CustomAgentforceView from "./CustomAgentforceView"; import { AgentforceService } from "@salesforce/react-native-agentforce"; // Register the component with AppRegistry -- this makes it available // for the native bridge to render via RCTRootView / ReactRootView. AppRegistry.registerComponent("CustomAgentforceView", () => CustomAgentforceView); // Register the mapping with the bridge async function setupCustomViews() { await AgentforceService.setViewProviderDelegate({ componentMap: { "copilot/richText": "CustomAgentforceView", "copilot/markdown": "CustomAgentforceView", "copilot/recordInfo": "CustomAgentforceView", "copilot/list": "CustomAgentforceView", }, }); } // Call during app initialization setupCustomViews(); ``` ### Component Data Interface ```tsx interface ViewProviderComponentData { definition: string; // Component definition (e.g. 'copilot/richText') name?: string; // Component name from SDK (may be null) properties: Record; // Key-value properties subComponents?: ViewProviderComponentData[]; // Nested sub-components } ``` ### Known Component Definitions - `copilot/list` - `copilot/recordInfo` - `copilot/markdown` - `copilot/richText` ### How It Works When you register a View Provider, the following flow occurs: 1. You register a `componentMap` mapping SDK definition strings to React Native component names. 2. The native bridge stores this map in `BridgeViewProvider`. 3. When the SDK needs to render a view, it calls `canHandle(definition)` on the view provider. 4. If the definition matches a key in the map, the provider returns `true`. 5. The SDK then calls `view()` (iOS) or `GetView()` (Android), which creates an `RCTRootView` (iOS) or `ReactRootView` (Android). 6. Your React Native component is rendered, receiving `componentData` as its initial props containing the `definition`, `name`, `properties`, and any `subComponents`. ### Feature Flag Requirement The `enableCustomViewProvider` feature flag must be `true`: ```tsx await AgentforceService.configure({ type: "service", // ... featureFlags: { enableCustomViewProvider: true }, }); ``` ### Clear the Delegate ```tsx await AgentforceService.clearViewProviderDelegate(); ``` ## Registration Timing Register delegates **before** calling `configure()` to ensure they're active when the SDK initializes: ```tsx // 1. Set up delegates AgentforceService.setLoggerDelegate({ onLog: handleLog }); AgentforceService.setNavigationDelegate({ onNavigate: handleNavigation }); await AgentforceService.setViewProviderDelegate({ componentMap: { /* ... */ }, }); // 2. Configure await AgentforceService.configure({ /* ... */ }); // 3. Launch await AgentforceService.launchConversation(); ``` ### Cleanup Always clean up delegates when they're no longer needed: ```tsx // In a React component: React.useEffect(() => { AgentforceService.setLoggerDelegate({ onLog: handleLog }); AgentforceService.setNavigationDelegate({ onNavigate: handleNav }); return () => { AgentforceService.clearLoggerDelegate(); AgentforceService.clearNavigationDelegate(); }; }, []); ``` Or call `destroy()` on app shutdown to clean up everything: ```tsx AgentforceService.destroy(); ``` ## See Also - [Configure the SDK](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-react-native-integration.md) - [Conversations](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-react-native-conversations.md) - [Limitations](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-react-native-limitations.md) # Deploy and Run Tests in the Command Line This topic outlines how to use the Testing API directly in the command line with the [Agentforce Vibes Extension](https://developer.salesforce.com/docs/platform/einstein-for-devs/guide/einstein-overview.html) and [Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/agent-dx/agent-dx.md) extensions. ## Prerequisites See the [Testing API workflow diagram](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-get-started.md#testing-api-workflow) for basic overview of how you can use the Testing API. For guidance on creating a project or authorizing your org in VS Code, see [Create Project](https://developer.salesforce.com/docs/platform/sfvscode-extensions/guide/create-project.html). Complete the required setup steps for the Testing API: - Create an [External Client App](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-connect.md#create-a-salesforce-app). - Turn on Agents, and have at least one active Agent. The API name for Agentforce (Default) is `Copilot_for_Salesforce`. ## Deploy Test Case Metadata **note:** For sample aiEvaluationDefinition XML, see [Build Tests in Metadata API](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-build-tests.md). To deploy the test definition to your org in the CLI, use the `project deploy start` command. For more information, see [Salesforce CLI Command Reference](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_project_commands_unified.htm#cli_reference_project_deploy_start_unified). ``` sf project deploy start ``` You can also deploy your test case with the [Command Palette](https://developer.salesforce.com/docs/platform/sfvscode-extensions/guide/vscode-commands.html?q=command%20palette) using `SFDX: Deploy This Source to Org`. ## Run Tests With Agentforce DX You can run tests in the command line with Agentforce DX using the `agent test run` command. To run tests with Agentforce DX, you'll need the API name of the agent you want to test as well as your development org. ``` sf agent test run --api-name Resort_Manager_Test --target-org my-dev-org ``` For more information on running tests via the CLI, see [Run Agent Tests with Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/agent-dx/agent-dx-test-run.md). ## View Test Results You can call Connect API endpoints via Agentforce DX with the `api request rest` command. ``` sf api request rest services/data/v63.0/einstein/ai-evaluations/runs/4KBSM00000000Xt4AI/results ``` Replace the runId in the example command to call the Get Test Results endpoint. # Display Names `enum class AgentforceDisplayNameType` Enumerates every user-visible string in the full-UI chat experience that you can override — titles, hints, button labels, and similar strings. Declared in package `com.salesforce.android.agentforcesdk.components.theme`. ## Setting display-name overrides Map an `AgentforceDisplayNameType` to your text in `AgentforceThemeOverrides`. Preserve any format placeholders (`%s`, `%d`, `%1$s`) present in the default string — the SDK substitutes real values into them at render time. ```kotlin import com.salesforce.android.agentforcesdk.components.theme.AgentforceDisplayNameType import com.salesforce.android.agentforcesdk.components.theme.AgentforceThemeOverrides val overrides = AgentforceThemeOverrides( displayNames = mapOf( AgentforceDisplayNameType.ServiceAIAgentName to "Acme Assistant", AgentforceDisplayNameType.InputTextPlaceholder to "Ask me anything…", AgentforceDisplayNameType.PreChatSubmitButton to "Connect with Support", ) ) ``` An empty override string is treated as unset, so the SDK's built-in string resource applies instead. ## Members (partial) The enum covers 45 customizable strings. These are the slots referenced elsewhere in the theming docs: | Member | Default text (English) | Appears on | | ---------------------- | ---------------------------- | ------------------- | | `ServiceAIAgentName` | Agent display name | Title bar, launcher | | `InputTextPlaceholder` | Message input placeholder | Composer input bar | | `PreChatSubmitButton` | Pre-chat submit button label | Pre-chat form | > This is not the complete list. Get the full `AgentforceDisplayNameType` enum, each string's default text, the screen it appears on, and its resource ID from the Android team before publishing. ## Reading display-name overrides at render time ```kotlin val theme = LocalAgentforceTheme.current val name = theme.getDisplayName(AgentforceDisplayNameType.ServiceAIAgentName) // null if not overridden ``` ## See also - [AgentforceThemeManager](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-theme-manager-android.md) — `getDisplayName(...)`. - [Custom Icons](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-icon-type-android.md) — the equivalent mechanism for customizable icons. # Download Agent Script Documentation Download the Agent Script documentation as markdown files so your coding agents can reference correct syntax, metadata deployment rules, and design patterns without web lookups. Use the files as grounding context for agentic coding and deployment tools, or search them locally. This download is updated weekly on Thursday evenings (PST), so download regularly to get the latest updates. ## Download and Set Up 1. Download the documentation bundle: [AgentScriptDocs.zip](https://resources.docs.salesforce.com/rel1/doc/en-us/static/misc/AgentScriptDocs.zip). 2. Unzip the file into your project workspace or the context source used by your coding agent. ## What's Included The bundle contains markdown files organized into these categories: | Folder | Contents | | :------------------------ | :----------------------------------------------------------------------------------------------- | | `agent-script/` | Language overview, Agent Script blocks, model config, flow of control, and managing your agent | | `agent-script/reference/` | Syntax, keywords, and semantics for Agent Script features | | `agent-script/patterns/` | Solutions for common tasks like multi-turn conversations, action chaining, and conditional logic | | `agent-script/examples/` | Complete agent implementations you can use as starting points | | `deploy-metadata/` | Instructions and examples on using metadata to deploy your agent to a new org | ## Use with Coding Agents Point your coding agent's context to the unzipped folder. For example, in a `CLAUDE.md` or similar context file: ```markdown Reference the Agent Script documentation in ./docs/agent-script/ for syntax and patterns. ``` Your agent can then look up syntax in the reference files and follow established patterns when generating Agent Script code. ## See the Agentforce Development Skill If you prefer a pre-packaged skill, use the [Agentforce Development Skill](https://github.com/forcedotcom/afv-library/tree/main/skills/developing-agentforce) to build, modify, debug, and deploy Agentforce agents with Agent Script. The Agentforce Development skill is part of the [Salesforce Skills Library](https://github.com/forcedotcom/afv-library). # Einstein Compute Service Errors The Einstein Compute service schedules and runs AI model training and data processing jobs that power Agentforce and other generative AI features. Errors from this service typically indicate that a job request was invalid or referenced a resource that doesn't exist, that the platform's compute infrastructure was temporarily unavailable or at capacity, or that an internal dependency encountered an unexpected failure. ## CCP_ACTUATOR_HEALTH_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_ACTUATOR_HEALTH_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_AOP_INSTRUMENTATION_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_AOP_INSTRUMENTATION_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_AUTH_SERVICE_FAILED The platform's authentication layer failed to respond to the service's request. The job can't start until the authentication layer is available again. This is usually a temporary issue. Trying again usually succeeds. This error occurs when: - The platform's authentication layer is temporarily overloaded or restarting. - A temporary network issue is preventing the service from reaching the authentication layer. ### How to Troubleshoot To resolve this error: 1. Wait a moment and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_AUTH_SERVICE_FAILED` - What you were doing when the error occurred ## CCP_BACKEND_BUSY The compute backend is at capacity with running jobs and can't accept this request right now. Waiting about a minute and trying again usually works. This error occurs when: - The backend has reached its maximum number of concurrent jobs. - The system is handling a high volume of requests. ### How to Troubleshoot To resolve this error: 1. Wait about a minute and try again. 2. If this happens consistently, consider spreading job submissions over a longer window. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_BACKEND_BUSY` - What you were trying to do and how often the error occurs ## CCP_BACKEND_CLIENT_FACTORY_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_BACKEND_CLIENT_FACTORY_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_BACKEND_HEALTH_CHECK_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_BACKEND_HEALTH_CHECK_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_BACKEND_NOT_AVAILABLE The compute backend required to run your job is temporarily unavailable. This is usually a temporary issue. Trying again usually succeeds. This error occurs when: - The backend is restarting or undergoing maintenance. - A temporary infrastructure issue is preventing the backend from accepting requests. ### How to Troubleshoot To resolve this error: 1. Wait a moment and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_BACKEND_NOT_AVAILABLE` - What you were doing when the error occurred ## CCP_BACKEND_NOT_FOUND The compute backend referenced in your request doesn't exist in this environment. Retrying won't help until the backend identifier is corrected. This error occurs when: - The backend identifier is incorrect or contains a typo. - The backend was removed or renamed. - The backend isn't available in your org's environment. ### How to Troubleshoot To resolve this error: 1. Verify the backend identifier is correct. 2. Confirm the backend is available in your environment. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_BACKEND_NOT_FOUND` - The backend identifier you specified ## CCP_BACKEND_VALIDATION_FAILED The compute backend configuration in your request failed validation. Retrying with the same request won't help. This error occurs when: - Required fields are missing or contain invalid values. - Field values don't meet the backend's validation constraints. ### How to Troubleshoot To resolve this error: 1. Review the error response for specific validation failures. 2. Correct the configuration and resubmit the request. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_BACKEND_VALIDATION_FAILED` - What you were trying to do when the error occurred ## CCP_CHAOS_TESTING_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_CHAOS_TESTING_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_CLASSIFICATION_NOT_FOUND The job classification referenced in your request doesn't exist. Retrying won't help until the classification is corrected. This error occurs when: - The classification identifier is misspelled or uses the wrong casing. - The classification has been removed or is no longer supported. - The classification isn't available in your org's environment. ### How to Troubleshoot To resolve this error: 1. Verify the classification identifier is correct. 2. Check the API documentation for supported classifications. 3. Update your request to use a valid classification identifier. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_CLASSIFICATION_NOT_FOUND` - The classification identifier you specified ## CCP_CREDENTIAL_MINTING_TIMEOUT The platform's credential provisioning step timed out before completing. This is usually a temporary issue. Trying again usually succeeds. This error occurs when: - Platform authentication services are under high load. - A temporary network delay is slowing down the credential provisioning process. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_CREDENTIAL_MINTING_TIMEOUT` - What you were doing when the error occurred ## CCP_D360_INVALID_TENANT The Data 360 tenant identifier in your request is invalid. Retrying won't help until the identifier is corrected. This error occurs when: - The tenant identifier is missing, malformed, or contains invalid characters. - The tenant identifier references a tenant that doesn't exist or is no longer active. ### How to Troubleshoot To resolve this error: 1. Verify the tenant identifier format matches the expected pattern. 2. Confirm the tenant exists and is active in Data 360. 3. Correct the tenant identifier and resubmit the request. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_D360_INVALID_TENANT` - What you were trying to do when the error occurred ## CCP_DAAS_SERVICE_BAD_REQUEST Your request to the platform's credential management layer contained invalid parameters. Retrying with the same request won't help. This error occurs when: - Required fields are missing or contain incorrect data types. - The request body doesn't match the expected format. ### How to Troubleshoot To resolve this error: 1. Review the error response for specific validation failures. 2. Correct the invalid parameters and retry the request. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_DAAS_SERVICE_BAD_REQUEST` - What you were trying to do when the error occurred ## CCP_DAAS_SERVICE_FAILED The platform's credential management layer is temporarily unavailable. Trying again usually succeeds. This error occurs when: - The credential management layer is under heavy load or restarting. - A temporary network issue is preventing the service from reaching its dependency. ### How to Troubleshoot To resolve this error: 1. Wait a moment and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_DAAS_SERVICE_FAILED` - What you were doing when the error occurred ## CCP_DATABASE_CONNECTION_FAILED The service can't connect to its database. This is usually a temporary issue. Trying again usually succeeds. This error occurs when: - The database is restarting or briefly unavailable. - A temporary network issue is preventing the service from reaching its database. ### How to Troubleshoot To resolve this error: 1. Wait a moment and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_DATABASE_CONNECTION_FAILED` - What you were doing when the error occurred ## CCP_DATABASE_QUERY_FAILED The service encountered an internal database error while processing your request. This is usually a temporary issue. Trying again usually succeeds. This error occurs when: - A temporary database issue caused the query to fail. - The service is experiencing elevated load. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_DATABASE_QUERY_FAILED` - What you were doing when the error occurred ## CCP_DATABASE_QUERY_TIMEOUT A database query took longer than the allowed time and was stopped. This is usually a temporary issue. Trying again usually succeeds. This error occurs when: - The database is under elevated load. - A temporary query performance issue caused the timeout. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_DATABASE_QUERY_TIMEOUT` - What you were doing when the error occurred ## CCP_DATABASE_TRANSACTION_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_DATABASE_TRANSACTION_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_DRIVER_POD_NOT_FOUND This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_DRIVER_POD_NOT_FOUND` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_DRIVER_POD_TERMINATION_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_DRIVER_POD_TERMINATION_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_IMBALANCE_DETECTION_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_IMBALANCE_DETECTION_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_INVALID_BACKEND_CONFIG This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_INVALID_BACKEND_CONFIG` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_INVALID_BACKEND_TYPE The backend type specified in your request isn't valid. Retrying won't help until the backend type is corrected. This error occurs when: - The backend type value is missing, malformed, or not recognized by the service. - The backend type isn't supported in your org's configuration. ### How to Troubleshoot To resolve this error: 1. Review the valid backend types in the API documentation. 2. Confirm the backend type is supported in your environment. 3. Correct the backend type and resubmit the request. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_INVALID_BACKEND_TYPE` - The backend type value you specified ## CCP_INVALID_EXTERNAL_JOB_ID The external job identifier in your request is invalid. Retrying won't help until the identifier is corrected. This error occurs when: - The identifier is malformed or contains invalid characters. - The identifier doesn't match the expected format. ### How to Troubleshoot To resolve this error: 1. Verify the external job identifier matches the expected format. 2. Correct the identifier and resubmit the request. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_INVALID_EXTERNAL_JOB_ID` - What you were trying to do when the error occurred ## CCP_INVALID_JOB_REQUEST The job request failed validation. Retrying with the same request won't help. This error occurs when: - The request body is malformed or contains invalid JSON. - Required fields contain incorrect data types or values outside the allowed range. - Fields don't pass the service's validation rules. ### How to Troubleshoot To resolve this error: 1. Review the error response for specific validation failures. 2. Check the API documentation for the correct request format. 3. Correct the invalid fields and resubmit. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_INVALID_JOB_REQUEST` - What you were trying to do when the error occurred ## CCP_INVALID_JOB_SPEC The job specification in your request failed validation. Retrying won't help until the specification is corrected. This error occurs when: - The job specification is malformed or missing required fields. - Field values in the specification don't meet validation constraints. ### How to Troubleshoot To resolve this error: 1. Review the error response for specific validation failures. 2. Check the job specification format in the API documentation. 3. Correct the invalid fields and resubmit. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_INVALID_JOB_SPEC` - What you were trying to do when the error occurred ## CCP_INVALID_KUBERNETES_CONFIG This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_INVALID_KUBERNETES_CONFIG` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_INVALID_REDIS_CONFIG This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_INVALID_REDIS_CONFIG` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_INVALID_SPARK_APPLICATION The data processing application configuration in your request failed validation. Retrying won't help until the configuration is corrected. This error occurs when: - The application configuration is missing required fields or contains invalid values. - Dependencies aren't correctly specified in the configuration. ### How to Troubleshoot To resolve this error: 1. Review the application configuration against the API documentation. 2. Ensure all required fields are present and correctly formatted. 3. Correct the configuration and resubmit. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_INVALID_SPARK_APPLICATION` - What you were trying to do when the error occurred ## CCP_INVALID_TEMPORAL_CONFIG This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_INVALID_TEMPORAL_CONFIG` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_JOB_AT_CAPACITY The service is at maximum capacity and can't accept new jobs right now. Waiting about a minute and trying again usually works. This error occurs when: - Too many jobs are currently running or queued. - The system's job capacity limit has been reached. ### How to Troubleshoot To resolve this error: 1. Wait about a minute and try again. 2. If this happens frequently, consider spreading job submissions over a longer time window. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_JOB_AT_CAPACITY` - What you were trying to do and how often the error occurs ## CCP_JOB_KILL_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_JOB_KILL_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_JOB_NOT_FOUND The job referenced in your request doesn't exist. Retrying won't help until the job identifier is corrected. This error occurs when: - The job identifier is incorrect or contains a typo. - The job was deleted or expired before this request was made. - The request is targeting the wrong org or environment. ### How to Troubleshoot To resolve this error: 1. Verify the job identifier is correct. 2. Confirm the job hasn't been deleted or expired. 3. Ensure you're querying the correct org and environment. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_JOB_NOT_FOUND` - The job identifier you specified ## CCP_JOB_PAYLOAD_SERIALIZATION_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_JOB_PAYLOAD_SERIALIZATION_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_JOB_STATUS_QUERY_FAILED The service can't retrieve job status right now due to a temporary platform issue. Trying again usually succeeds. This error occurs when: - An upstream service dependency is temporarily unavailable. - A temporary network issue is preventing the service from checking job status. ### How to Troubleshoot To resolve this error: 1. Wait a moment and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_JOB_STATUS_QUERY_FAILED` - What you were doing when the error occurred ## CCP_JOB_SUBMISSION_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_JOB_SUBMISSION_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_JSON_DESERIALIZATION_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_JSON_DESERIALIZATION_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_JSON_SERIALIZATION_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_JSON_SERIALIZATION_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_KAFKA_PUBLISH_FAILED The service couldn't publish an event to the platform's internal messaging layer. This is usually a temporary issue. Trying again usually succeeds. This error occurs when: - The internal messaging layer is temporarily unavailable or under high load. - A temporary network issue is preventing the publish operation. ### How to Troubleshoot To resolve this error: 1. Wait a moment and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_KAFKA_PUBLISH_FAILED` - What you were doing when the error occurred ## CCP_KUBERNETES_API_TIMEOUT A call to the platform's compute infrastructure timed out. This is usually a temporary issue. Trying again usually succeeds. This error occurs when: - The platform's compute infrastructure is under elevated load. - A temporary network delay caused the timeout. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_KUBERNETES_API_TIMEOUT` - What you were doing when the error occurred ## CCP_KUBERNETES_CLIENT_ERROR Your request to the platform's compute infrastructure contained invalid or malformed data. Retrying won't help until the issue is corrected. This error occurs when: - The request is missing required fields or contains invalid values. - The request doesn't meet the expected format for this operation. ### How to Troubleshoot To resolve this error: 1. Review the error response for specific validation failures. 2. Check the API documentation for the correct request format. 3. Correct the request and resubmit. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_KUBERNETES_CLIENT_ERROR` - What you were trying to do when the error occurred ## CCP_KUBERNETES_CLIENT_INIT_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_KUBERNETES_CLIENT_INIT_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_KUBERNETES_SERVER_ERROR The platform's compute infrastructure returned an error. This is usually a temporary issue. Trying again usually succeeds. This error occurs when: - The compute infrastructure is temporarily overloaded or restarting. - A temporary network issue is affecting compute operations. ### How to Troubleshoot To resolve this error: 1. Wait a moment and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_KUBERNETES_SERVER_ERROR` - What you were doing when the error occurred ## CCP_LEAD_MANAGEMENT_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_LEAD_MANAGEMENT_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_LEAD_RELEASE_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_LEAD_RELEASE_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_LEADER_ELECTION_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_LEADER_ELECTION_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_METRICS_RECORDING_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_METRICS_RECORDING_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_MISSING_CONFIGURATION This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_MISSING_CONFIGURATION` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_MISSING_REQUIRED_FIELD Your request is missing a required field. The Einstein Compute service can't process the request without all required fields. Retrying won't help until the missing field is included. This error occurs when: - A required field was omitted from the request body or parameters. - An empty or null value was provided for a field that requires a value. ### How to Troubleshoot To resolve this error: 1. Review the error response to identify which field is missing. 2. Check the API documentation for the endpoint's required fields. 3. Add the missing field with a valid value and retry. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_MISSING_REQUIRED_FIELD` - What you were trying to do when the error occurred ## CCP_NO_BACKEND_FOUND No compute backend matching your request was found in this environment. Retrying won't help until the backend configuration is corrected. This error occurs when: - The backend with the specified type or name doesn't exist. - The backend has been removed or renamed. - The backend isn't available in your org's environment. ### How to Troubleshoot To resolve this error: 1. Verify the backend identifier is correct. 2. Confirm the backend is available in your environment. 3. If a specific backend isn't required, try using the default backend. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_NO_BACKEND_FOUND` - The backend identifier or type you specified ## CCP_OUTBOX_EVENT_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_OUTBOX_EVENT_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_OUTBOX_RELAY_FAILED The service encountered a temporary error forwarding an internal event. This is usually a temporary issue. Trying again usually succeeds. This error occurs when: - The internal event relay is temporarily unavailable. - A temporary platform issue prevented the event from being forwarded. ### How to Troubleshoot To resolve this error: 1. Wait a moment and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_OUTBOX_RELAY_FAILED` - What you were doing when the error occurred ## CCP_RAY_API_TIMEOUT A call to the platform's compute layer timed out. This is usually a temporary issue. Trying again usually succeeds. This error occurs when: - The platform's compute layer is under elevated load. - A temporary network delay caused the timeout. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_RAY_API_TIMEOUT` - What you were doing when the error occurred ## CCP_RAY_CLIENT_ERROR Your request to the platform's compute layer contained invalid or malformed data. Retrying won't help until the issue is corrected. This error occurs when: - The request is missing required fields or contains invalid values. - The request doesn't meet the expected format. ### How to Troubleshoot To resolve this error: 1. Review the error response for specific validation failures. 2. Check the API documentation for the correct request format. 3. Correct the request and resubmit. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_RAY_CLIENT_ERROR` - What you were trying to do when the error occurred ## CCP_RAY_SERVER_ERROR The platform's compute layer returned an error. This is usually a temporary issue. Trying again usually succeeds. This error occurs when: - The compute layer is temporarily overloaded or restarting. - A temporary network issue is affecting compute operations. ### How to Troubleshoot To resolve this error: 1. Wait a moment and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_RAY_SERVER_ERROR` - What you were doing when the error occurred ## CCP_REBALANCING_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_REBALANCING_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_RECOVERABLE_JOB_ERROR The service encountered a temporary problem while processing your job. The platform retries automatically. If you still see this error, trying again usually succeeds. This error occurs when: - A required service was temporarily unavailable during job processing. - A temporary network or timeout issue occurred while submitting or checking job status. ### How to Troubleshoot To resolve this error: 1. Wait a moment and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_RECOVERABLE_JOB_ERROR` - What you were doing when the error occurred ## CCP_REDIS_CONNECTION_FAILED The service can't connect to the platform's caching layer. This is usually a temporary issue. Trying again usually succeeds. This error occurs when: - The caching layer is temporarily restarting or unavailable. - A temporary network issue is preventing the connection. ### How to Troubleshoot To resolve this error: 1. Wait a moment and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_REDIS_CONNECTION_FAILED` - What you were doing when the error occurred ## CCP_REDIS_LOCK_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_REDIS_LOCK_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_REDIS_OPERATION_TIMEOUT An operation on the platform's caching layer timed out. This is usually a temporary issue. Trying again usually succeeds. This error occurs when: - The caching layer is under elevated load. - A temporary network delay caused the timeout. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_REDIS_OPERATION_TIMEOUT` - What you were doing when the error occurred ## CCP_REDIS_STREAM_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_REDIS_STREAM_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_SECRET_WRITE_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_SECRET_WRITE_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_SPARK_APPLICATION_ALREADY_EXISTS A data processing application with the same identifier already exists. Retrying won't help until the conflict is resolved. This error occurs when: - You're trying to register an application that already exists in this environment. - The application identifier isn't unique. ### How to Troubleshoot To resolve this error: 1. Check whether an application with this identifier already exists. 2. Use a different identifier or update the existing application instead of creating a new one. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_SPARK_APPLICATION_ALREADY_EXISTS` - The application identifier you specified ## CCP_SPARK_APPLICATION_NOT_FOUND The data processing application referenced in your request doesn't exist. Retrying won't help until the identifier is corrected. This error occurs when: - The application identifier is incorrect or contains a typo. - The application was removed. ### How to Troubleshoot To resolve this error: 1. Verify the application identifier is correct. 2. Confirm the application hasn't been removed. 3. Correct the identifier and resubmit. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_SPARK_APPLICATION_NOT_FOUND` - The application identifier you specified ## CCP_SPARK_APPLICATION_STATUS_PARSE_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_SPARK_APPLICATION_STATUS_PARSE_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_STREAM_CONSUMPTION_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_STREAM_CONSUMPTION_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_STREAM_PROCESSING_FAILED An internal stream processing error occurred. This is usually a temporary issue. Trying again usually succeeds. This error occurs when: - A temporary internal processing error prevented the stream operation from completing. - The service is experiencing elevated load. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_STREAM_PROCESSING_FAILED` - What you were doing when the error occurred ## CCP_STREAM_TRIM_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_STREAM_TRIM_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_STS_TOKEN_BAD_REQUEST Your request to the platform's authentication token service contained invalid parameters. Retrying won't help until the parameters are corrected. This error occurs when: - Required fields are missing or incorrectly formatted in the token request. - The requested permissions don't match what's allowed for your service. - Token request parameters contain invalid values. ### How to Troubleshoot To resolve this error: 1. Review the error response for specific validation failures. 2. Verify all required fields are present and correctly formatted. 3. Correct the parameters and resubmit. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_STS_TOKEN_BAD_REQUEST` - What you were trying to do when the error occurred ## CCP_STS_TOKEN_GENERATION_FAILED The platform's authentication token service is temporarily unavailable. Trying again usually succeeds. This error occurs when: - The authentication token service is under heavy load or restarting. - A temporary network issue is preventing token generation. ### How to Troubleshoot To resolve this error: 1. Wait a moment and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_STS_TOKEN_GENERATION_FAILED` - What you were doing when the error occurred ## CCP_TEMPORAL_WORKFLOW_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_TEMPORAL_WORKFLOW_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_TEMPORAL_WORKFLOW_TIMEOUT This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_TEMPORAL_WORKFLOW_TIMEOUT` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## CCP_UNSUPPORTED_BACKEND The compute backend type you specified isn't supported. Retrying won't help until you switch to a supported backend type. This error occurs when: - The backend type isn't available in this service version or your org's configuration. - The backend type has been deprecated or isn't enabled for your environment. ### How to Troubleshoot To resolve this error: 1. Check the API documentation for supported backend types. 2. Update your request to use a supported backend type. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_UNSUPPORTED_BACKEND` - The backend type you specified ## CCP_VAULT_FETCH_FAILED The platform's secrets management layer failed to retrieve a required configuration. This is usually a temporary issue. Trying again usually succeeds. This error occurs when: - The secrets management layer is temporarily unavailable or under high load. - A temporary network issue is preventing the service from retrieving the configuration. ### How to Troubleshoot To resolve this error: 1. Wait a moment and try again. 2. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_VAULT_FETCH_FAILED` - What you were doing when the error occurred ## CCP_VAULT_INVALID_CONFIG The secrets management configuration in your request is invalid or incomplete. Retrying won't help until the configuration is corrected. This error occurs when: - Required configuration fields are missing or contain invalid values. - The path or namespace format doesn't match what's expected. - The authentication method specification doesn't match the configured setup. ### How to Troubleshoot To resolve this error: 1. Review the error response for specific validation failures. 2. Verify all configuration fields are present and correctly formatted. 3. Correct the configuration and resubmit. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_VAULT_INVALID_CONFIG` - What you were trying to do when the error occurred ## CCP_VAULT_PATH_OR_FIELD_NOT_FOUND The path or field referenced in your request doesn't exist in the platform's secrets management layer. Retrying won't help until the reference is corrected. This error occurs when: - The path doesn't exist or has been removed. - The field name is misspelled or doesn't exist at the specified path. - The secret was relocated. ### How to Troubleshoot To resolve this error: 1. Verify the path and field name are correct. 2. Confirm the secret exists and hasn't been relocated or removed. 3. Correct the reference and resubmit. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_VAULT_PATH_OR_FIELD_NOT_FOUND` - What you were trying to do when the error occurred ## CCP_VAULT_UNAUTHORIZED_PATH The request doesn't have permission to access the specified path in the platform's secrets management layer. Retrying won't help until the permissions issue is resolved. This error occurs when: - The credentials used for this request don't have access to the requested path. - The path is restricted to specific roles or services. - The authentication credentials have insufficient privileges. ### How to Troubleshoot To resolve this error: 1. Verify that your org's configuration has the necessary access permissions for this operation. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CCP_VAULT_UNAUTHORIZED_PATH` - What you were trying to do when the error occurred # ElevenLabs Flash v2 Voices This page lists the ElevenLabs Flash v2 voice personas and the English locales each one supports. Use Flash v2 for English; for other languages, use [ElevenLabs Flash v2.5 Voices](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice-catalog-flash-2-5.md) instead. To use one, select the ElevenLabs Flash v2 model and set a `persona_id` in the `modality voice` block. If you select ElevenLabs Flash v2 without a `persona_id`, the agent falls back to the voice marked **(default)**. For how to select a model and configure a voice, see [Configure Voice Models in Agent Script](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice.md). ## English (Australia) - en_AU | Voice | Gender | Voice ID | Description | Default Parameter Values | | :------------- | :----- | :------------- | :------------------------------------------------------------------------- | :--------------------------------------------- | | Dallas | Male | `b136a8eefd7f` | High-quality voice with a clear and authoritative delivery. | similarity: 0.75, speed: 1.07, stability: 0.43 | | Greg | Male | `942fa229b185` | Lively voice with a natural and engaging energy. | similarity: 0.75, speed: 0.86, stability: 0.6 | | Jack (default) | Male | `1ef01b886887` | Articulate and well-modulated voice with a professional tone. | similarity: 0.75, speed: 0.93, stability: 0.8 | | Jason | Male | `fe69e4a8e524` | Helpful voice with a light and approachable tone. | similarity: 0.75, speed: 1, stability: 0.75 | | Jess | Female | `6084390808d7` | Conversational voice combining professional articulation with a warm tone. | similarity: 0.75, speed: 1.06, stability: 0.61 | | Joseph | Male | `112cfe92f2e9` | Composed voice with rich depth and a reassuring presence. | similarity: 0.75, speed: 1.02, stability: 0.75 | | Kate | Female | `89fe7ded7864` | Conversational voice with a grounded and composed quality. | similarity: 0.75, speed: 0.96, stability: 0.8 | | Marty | Male | `d8665f83c4c5` | Light-accented voice with a professional and composed tone. | similarity: 0.75, speed: 0.85, stability: 0.7 | | Matilda | Female | `382e950805fe` | Bright voice with an easygoing and upbeat quality. | similarity: 0.75, speed: 1.08, stability: 0.75 | | Matthew | Male | `4d55fd1cb203` | Grounded voice with an unpretentious and relatable quality. | similarity: 0.75, speed: 0.95, stability: 0.4 | | Nathan | Male | `095dafbbb5e5` | Smooth voice with an effortless and understated quality. | similarity: 0.75, speed: 1.02, stability: 0.45 | ## English (United Kingdom) - en_GB | Voice | Gender | Voice ID | Description | Default Parameter Values | | :------------- | :----- | :------------- | :-------------------------------------------------------------------------- | :-------------------------------------------- | | Archer | Male | `81fe7b2dc8bd` | Fine-tuned British voice with a natural and polished delivery. | similarity: 0.75, speed: 1, stability: 0.5 | | Isla | Female | `f0cb97499793` | Gentle voice with a smooth and slightly airy timbre. | similarity: 0.75, speed: 0.92, stability: 0.4 | | Lizzie | Female | `a512197f9800` | Distinctly London-accented voice with an inviting and engaging quality. | similarity: 0.75, speed: 1, stability: 0.75 | | Noah (default) | Male | `16c896e36f6b` | Smooth voice with a slightly higher timbre that's clear and informative. | similarity: 0.75, speed: 1.1, stability: 0.4 | | Ollie | Male | `443c01108094` | Clear British voice with warmth and ease in every delivery. | similarity: 0.75, speed: 0.94, stability: 0.5 | | Rory | Male | `ddfe812d6709` | Dynamic British voice with natural breath pauses and an unscripted cadence. | similarity: 0.75, speed: 1, stability: 0.5 | | Steffy | Female | `908a67f0341c` | Balanced voice with a composed and approachable delivery. | similarity: 0.75, speed: 0.95, stability: 0.5 | ## English (United States) - en_US | Voice | Gender | Voice ID | Description | Default Parameter Values | | :------------- | :----- | :------------- | :-------------------------------------------------------------------------------------------------- | :--------------------------------------------- | | Adalina | Female | `23ab4fd39384` | Tender voice that radiates kindness with a thoughtful tone. | similarity: 0.75, speed: 1.02, stability: 0.45 | | Alex | Male | `5e54d6621466` | Bold voice with infectious energy and flair. | similarity: 0.75, speed: 1.08, stability: 0.4 | | April | Female | `a029af9d692c` | Voice that reads numbers naturally and with even delivery. | similarity: 0.75, speed: 1, stability: 0.5 | | Asher | Male | `eb2e2945be20` | Warm voice that communicates with ease and sincerity. | similarity: 0.75, speed: 0.94, stability: 0.75 | | Bella | Female | `91b29cfbd3c6` | Warm bright and professional with a Standard American accent. Polished clear and easy to listen to. | similarity: 0.75, speed: 1, stability: 0.4 | | Brady | Male | `44e49d801798` | Friendly voice that builds trust and communicates with clarity. | similarity: 0.75, speed: 1, stability: 0.65 | | Burt | Male | `16eaeefff22d` | Smooth voice that guides listeners with clarity and depth. | similarity: 0.75, speed: 1.02, stability: 0.75 | | Cassidy | Female | `c12ddaf07787` | Confident voice with a composed and assured quality. | similarity: 0.75, speed: 0.94, stability: 0.8 | | Chad | Male | `6fc0553dbeae` | Voice with a slightly textured quality and a youthful edge. | similarity: 0.56, speed: 0.96, stability: 0.75 | | Chris | Male | `b545a02a049c` | Smooth voice with a relaxed and effortless quality. | similarity: 0.75, speed: 0.91, stability: 0.8 | | Christina | Female | `74752e92d40e` | Accessible voice with an approachable quality. | similarity: 0.75, speed: 0.96, stability: 0.56 | | Clara | Female | `36cb9127e34d` | Bright voice with clarity and a cooperative quality. | similarity: 0.75, speed: 1.09, stability: 0.59 | | Cliff | Male | `6d87aa01b753` | Extremely natural voice with neutral emotion and measured delivery. | similarity: 0.75, speed: 1, stability: 0.5 | | Fiona | Female | `394472f49a1f` | Voice with a lower pitch and a natural cadence. | similarity: 0.75, speed: 1, stability: 0.5 | | Gregg | Male | `748267289fcc` | No-nonsense voice with an honest and composed quality. | similarity: 0.75, speed: 0.94, stability: 0.4 | | Heath | Female | `7993046a2f19` | Straightforward voice with a direct and collegial tone. | similarity: 0.75, speed: 0.87, stability: 0.75 | | Heather | Female | `2c714a371c4b` | Even-keeled voice with an unpretentious and understated quality. | similarity: 0.5, speed: 1.06, stability: 0.5 | | Hope | Female | `e30278798fa3` | Youthful voice with a warm and conversational quality. | similarity: 0.75, speed: 1, stability: 0.5 | | Jahmal | Male | `b66d5abcf5e5` | Energetic voice with infectious enthusiasm and dynamic presence. | similarity: 0.75, speed: 0.94, stability: 0.8 | | Jalisa | Female | `dfb8f96ff8de` | Voice with precise articulation and a measured tone. | similarity: 0.75, speed: 1, stability: 0.5 | | Jerry | Male | `104b87b5ed18` | Clear and easygoing voice with a natural conversational quality. | similarity: 0.75, speed: 0.94, stability: 0.8 | | Jessica | Female | `8bc1d6d869fd` | Articulate voice with a cooperative and clear delivery. | similarity: 0.75, speed: 1.06, stability: 0.6 | | Josh | Male | `1e98b5f43740` | Relaxed voice with a natural and unforced quality. | similarity: 0.75, speed: 0.95, stability: 0.8 | | Juniper | Female | `a0b66f728333` | Polished voice that delivers content with confidence and clarity. | similarity: 0.75, speed: 0.94, stability: 0.8 | | Kai | Female | `c6d7eae8bd64` | Gentle Southern voice with a measured and composed tone. | similarity: 0.75, speed: 1.06, stability: 0.5 | | Kris | Male | `d9891f65db0a` | Deep voice with studio-quality sound and a professional demeanor. | similarity: 0.6, speed: 1.08, stability: 0.4 | | Kyle | Male | `e815ba5811ce` | Voice that delivers numbers and names with consistent precision. | similarity: 0.75, speed: 1.12, stability: 0.5 | | Laura | Female | `cd62c7e2a3ee` | Enthusiastic voice with charm and a quirky personality. | similarity: 0.75, speed: 1, stability: 0.8 | | Lemania | Female | `0cda087861e1` | Soulful Southern drawl with a deeply reassuring quality. | similarity: 0.75, speed: 1.1, stability: 0.75 | | Lisa | Female | `2186aacff000` | Relaxed voice with a natural human touch. | similarity: 0.75, speed: 1.08, stability: 0.4 | | Liz | Female | `d25d8e8e2789` | Bright voice with lifelike energy and warmth. | similarity: 0.75, speed: 1.02, stability: 0.5 | | Marcus | Male | `c21718fe66b6` | New England-accented voice with a distinctive regional character. | similarity: 0.75, speed: 0.94, stability: 0.5 | | Mark (default) | Male | `f64af13e6fb0` | Casual voice with an easygoing and approachable quality. | similarity: 0.75, speed: 1, stability: 0.65 | | Olivia | Female | `80d9e72b42ba` | Calm British voice with a slightly lower pitch and smooth timbre. | similarity: 0.75, speed: 1, stability: 0.4 | | Pete | Male | `f28f0f945cdf` | Approachable voice with a friendly and explanatory quality. | similarity: 0.75, speed: 1.04, stability: 0.75 | | Tessa | Female | `ccd67ad88bb7` | Voice with youthful ease and an effortless quality. | similarity: 0.67, speed: 1.06, stability: 0.59 | | Todd | Male | `d9833727bcb8` | Conversational voice with a natural and composed delivery. | similarity: 0.75, speed: 1, stability: 0.8 | | Victoria | Female | `961c4c0b685d` | Heartfelt voice with a casual and relatable quality. | similarity: 0.5, speed: 0.92, stability: 0.8 | | Will | Male | `1d97e7d6a179` | Distinctive voice with relaxed energy and an easygoing quality. | similarity: 0.75, speed: 1, stability: 0.8 | ## Related Topics - [Voice Catalog for Agentforce Voice](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice-catalog.md) - [Configure Voice Models in Agent Script](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice.md) - [ElevenLabs](https://elevenlabs.io/) # ElevenLabs Flash v2.5 Voices This page lists the ElevenLabs Flash v2.5 voice personas and the locales each one supports. Use Flash v2.5 for non-English languages; for English, use [ElevenLabs Flash v2 Voices](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice-catalog-flash-2.md) instead. To use one, select the ElevenLabs Flash v2.5 model and set a `persona_id` in the `modality voice` block. If you select ElevenLabs Flash v2.5 without a `persona_id`, the agent falls back to the voice marked **(default)**. For how to select a model and configure a voice, see [Configure Voice Models in Agent Script](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice.md). ## Arabic (Egypt) - ar_EG | Voice | Gender | Voice ID | Description | Default Parameter Values | | :------------- | :----- | :------------- | :------------------------------------------------------------------------- | :----------------------------------------- | | Amir (default) | Male | `0654d6204343` | Rich Egyptian voice with clarity and wide emotional range. | similarity: 0.75, speed: 1, stability: 0.8 | | Hoda | Female | `a33002d34f14` | Distinctive Egyptian voice with an expressive and captivating quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Omar | Male | `bbed2ec8f2fe` | Confident voice with a clear Egyptian accent and professional tone. | similarity: 0.75, speed: 1, stability: 0.8 | | Yasmine | Female | `f73e1acecd05` | Natural Egyptian voice with an effortlessly conversational and human tone. | similarity: 0.75, speed: 1, stability: 0.8 | ## Arabic (Saudi Arabia) - ar_SA | Voice | Gender | Voice ID | Description | Default Parameter Values | | :------------- | :----- | :------------- | :---------------------------------------------------------------- | :----------------------------------------- | | Ali | Male | `50ba02cf0687` | Calm voice with a resonant and balanced professional delivery. | similarity: 0.75, speed: 1, stability: 0.8 | | Heba | Female | `1d5f34c2f58d` | Calm voice with a trustworthy and emotionally grounded quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Layan | Female | `88cbb2db2cf3` | Professional voice with a subtle Najdi quality and composed tone. | similarity: 0.75, speed: 1, stability: 0.8 | | Saud (default) | Male | `97c737eadf56` | Deep voice with a formal and trustworthy Saudi delivery. | similarity: 0.75, speed: 1, stability: 0.8 | ## Arabic (U.A.E.) - ar_AE | Voice | Gender | Voice ID | Description | Default Parameter Values | | :-------------- | :----- | :------------- | :-------------------------------------------------------------- | :----------------------------------------- | | Amira (default) | Female | `bd98faf345b9` | Composed voice with a smooth Gulf accent and dignified tone. | similarity: 0.75, speed: 1, stability: 0.8 | | Latifa | Female | `ac3d863402db` | Resonant voice with a rich Gulf accent and reassuring presence. | similarity: 0.75, speed: 1, stability: 0.8 | | Rashid | Male | `c863266e0733` | Narrative voice with a close and present storytelling quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Sultan | Male | `640384705fd6` | Clear Emirati voice with a confident and natural delivery. | similarity: 0.75, speed: 1, stability: 0.8 | ## Chinese (Simplified) - zh_CH | Voice | Gender | Voice ID | Description | Default Parameter Values | | :--------------- | :----- | :------------- | :------------------------------------------------------------- | :----------------------------------------- | | Amy | Female | `fcc522c786ac` | Natural voice with a relaxed and friendly conversational tone. | similarity: 0.75, speed: 1, stability: 0.8 | | Haoran (default) | Male | `2368d3f42af9` | Deep voice with a steady tone and expressive delivery. | similarity: 0.75, speed: 1, stability: 0.8 | | Sage | Female | `cfbb00e45d34` | Soothing voice with a calm and gently intimate quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Siqi | Male | `6a7e32d2eb73` | Warm voice with a gentle rhythm and natural articulation. | similarity: 0.75, speed: 1, stability: 0.8 | | Wei | Male | `5171cfe1fdd5` | Friendly voice with a calm and conversational delivery. | similarity: 0.75, speed: 1, stability: 0.8 | ## Chinese (Traditional) - zh_TW | Voice | Gender | Voice ID | Description | Default Parameter Values | | :------------- | :----- | :------------- | :----------------------------------------------------------- | :----------------------------------------- | | Anna (default) | Female | `8350d4d5a297` | Bright voice with a youthful and effortlessly engaging tone. | similarity: 0.75, speed: 1, stability: 0.8 | ## Croatian - hr_HR | Voice | Gender | Voice ID | Description | Default Parameter Values | | :---- | :----- | :------------- | :---------------------------------------------------- | :----------------------------------------- | | Karlo | Male | `2020b49a9a0f` | Pleasant voice with a natural and easygoing delivery. | similarity: 0.75, speed: 1, stability: 0.8 | | Luka | Male | `aa82215beefa` | Neutral voice with a steady and composed quality. | similarity: 0.75, speed: 1, stability: 0.8 | ## Czech - cs_CZ | Voice | Gender | Voice ID | Description | Default Parameter Values | | :------ | :----- | :------------- | :--------------------------------------------------------------- | :----------------------------------------- | | Antonín | Male | `be39025c669f` | Velvety voice with a natural and approachable quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Iveta | Female | `a9966460efef` | Reflective voice with gentle articulation and a reassuring tone. | similarity: 0.75, speed: 1, stability: 0.8 | ## Danish - da_DK | Voice | Gender | Voice ID | Description | Default Parameter Values | | :---- | :----- | :------------- | :------------------------------------------------------ | :----------------------------------------- | | Klara | Female | `b679a9a426cd` | Gentle voice that conveys reassurance with a warm tone. | similarity: 0.75, speed: 1, stability: 0.8 | | Peder | Male | `c04b0a1fee52` | Measured voice with a steady and informative delivery. | similarity: 0.75, speed: 1, stability: 0.8 | ## Dutch - nl | Voice | Gender | Voice ID | Description | Default Parameter Values | | :--------------- | :----- | :------------- | :------------------------------------------------------------------ | :-------------------------------------------- | | James | Male | `2b87094b3e79` | Native Dutch voice with a full and authoritative quality. | similarity: 0.75, speed: 1, stability: 0.5 | | Jann | Male | `99d1bea02a75` | Warm voice with a natural calmness and clear delivery. | similarity: 0.75, speed: 1.02, stability: 0.5 | | Lara | Female | `2f145b8bc16a` | Enthusiastic Flemish/Dutch voice with a crisp and composed quality. | similarity: 0.75, speed: 1, stability: 0.5 | | Melanie | Female | `4d2c43257932` | Clear voice with a youthful and engaging quality. | similarity: 0.75, speed: 0.92, stability: 0.5 | | Pieter (default) | Male | `0e9dac8d42a6` | Reliable voice with a warm and informative quality. | similarity: 0.75, speed: 1, stability: 0.5 | | Ruth | Female | `8ff6fe79c1f9` | Recognizable voice in a casual register. | similarity: 0.75, speed: 1, stability: 0.8 | ## Filipino - fil_PH | Voice | Gender | Voice ID | Description | Default Parameter Values | | :------ | :----- | :------------- | :----------------------------------------------------------------- | :----------------------------------------- | | Avelina | Female | `9216c2ba9dbb` | Graceful voice that conveys sincerity and composed authority. | similarity: 0.75, speed: 1, stability: 0.8 | | Pocholo | Male | `3c1ff3976646` | Warm voice with a storytelling quality that inspires and connects. | similarity: 0.75, speed: 1, stability: 0.8 | ## Finnish - fi_FI | Voice | Gender | Voice ID | Description | Default Parameter Values | | :----- | :----- | :------------- | :------------------------------------------------------------------- | :----------------------------------------- | | Jussi | Male | `258414aa44ca` | Distinctively accented voice with a light-hearted and humorous tone. | similarity: 0.75, speed: 1, stability: 0.8 | | Viisas | Male | `2c53d5f690a4` | Clear voice that sounds trustworthy and authoritative. | similarity: 0.75, speed: 1, stability: 0.8 | ## French (Canada) - fr_CA | Voice | Gender | Voice ID | Description | Default Parameter Values | | :---------------- | :----- | :------------- | :------------------------------------------------------------------ | :--------------------------------------------- | | Amélie | Female | `8d0d4ec2eb4c` | Credible voice with a clear Quebec accent and precise articulation. | similarity: 0.75, speed: 1, stability: 0.8 | | Gabrielle | Female | `528f7a6a10ba` | Soft voice with a clear Quebec accent and a smooth tone. | similarity: 0.75, speed: 0.96, stability: 0.45 | | Haseeb | Male | `fe07a5869101` | Informative voice with a clear and instructive quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Jeanne | Female | `7c57b201a8e0` | Warm voice with a patient and instructive quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Léo | Male | `3ecc945a930c` | Reassuring voice with a smiling tone and an uplifting quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Marie | Female | `8ffb9c890df4` | Calm voice that inspires confidence with a smiling quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Mathieu (default) | Male | `485dfedf772b` | Clear voice with a calming and reassuring tone. | similarity: 0.75, speed: 0.96, stability: 0.45 | ## French (France) - fr | Voice | Gender | Voice ID | Description | Default Parameter Values | | :-------------- | :----- | :------------- | :--------------------------------------------------------------- | :--------------------------------------------- | | Hugues | Male | `b21b0377d607` | Warm voice with a confident lower-mid resonance. | similarity: 0.75, speed: 1, stability: 0.8 | | Koraly | Female | `a72016284eaf` | Expressive voice that adapts naturally to varied content. | similarity: 0.75, speed: 1, stability: 0.8 | | Louis (default) | Male | `4f708167ff27` | Pleasing voice that is smooth and somewhat deep. | similarity: 0.75, speed: 1, stability: 0.44 | | Lucie | Female | `8438b254ab85` | Realistic voice with a natural and approachable tone. | similarity: 0.75, speed: 0.95, stability: 0.8 | | Marcel | Male | `84062cf78d56` | Conversational voice with an approachable and easygoing quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Sophie | Female | `2c6cef2170c8` | Soft voice with a precise European accent and gentle tone. | similarity: 0.75, speed: 0.92, stability: 0.92 | | Theo | Male | `7873dd5ab5fa` | Optimistic voice with an upbeat and engaging quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Victoire | Female | `d7b7d7cff5b8` | Fluid voice with exceptional clarity and engaging presence. | similarity: 0.75, speed: 1, stability: 0.8 | ## German - de | Voice | Gender | Voice ID | Description | Default Parameter Values | | :-------------- | :----- | :------------- | :----------------------------------------------------------------------------- | :----------------------------------------- | | Anton (default) | Male | `83707dbabdbd` | Calm voice with a deliberate and conversational delivery. | similarity: 0.5, speed: 1, stability: 0.5 | | Ben | Male | `2b4c201ef1cf` | Versatile voice that switches effortlessly from upbeat to warm and reassuring. | similarity: 0.75, speed: 1, stability: 0.8 | | Ela | Female | `7f0437ca7cc8` | Curious voice with natural sparkle and a lively quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Felix | Male | `828fa54d7fe8` | Clear voice with neutral pronunciation and a consistent delivery. | similarity: 0.75, speed: 1, stability: 0.8 | | Frieda | Female | `019e60b19583` | Natural voice with a medium pitch and conversational delivery. | similarity: 0.75, speed: 1, stability: 0.5 | | Irene | Female | `4756f31134ba` | Warm voice with soft intonation and a slightly humorous tone. | similarity: 0.75, speed: 1, stability: 0.8 | | Julia | Female | `0fbe4455f2ed` | Calm voice with a composed and reliable delivery. | similarity: 0.75, speed: 1, stability: 0.8 | | Marc | Male | `81ad417ab1ff` | Highly pleasant voice with a smooth and sustained delivery. | similarity: 0.75, speed: 1, stability: 0.8 | | Rebecca | Female | `21cc66845f93` | Clear voice that builds trust and explains complex topics with ease. | similarity: 0.75, speed: 1, stability: 0.8 | | Simon | Male | `236f709500e0` | Youthful voice with natural pauses and a thoughtful delivery. | similarity: 0.75, speed: 1, stability: 0.8 | ## Greek - el_GR | Voice | Gender | Voice ID | Description | Default Parameter Values | | :------- | :----- | :------------- | :------------------------------------------------------- | :----------------------------------------- | | Georgios | Male | `ea4d1ff51a17` | Measured voice with a naturally conversational delivery. | similarity: 0.75, speed: 1, stability: 0.8 | | Marta | Female | `87d68c516261` | Versatile voice with a clear and dynamic delivery. | similarity: 0.75, speed: 1, stability: 0.8 | ## Hindi - hi | Voice | Gender | Voice ID | Description | Default Parameter Values | | :-------------- | :----- | :------------- | :-------------------------------------------------------------------------------------- | :-------------------------------------------- | | Aakash | Male | `27eca90de0e4` | Widely recognized voice with a supportive and composed tone. | similarity: 0.75, speed: 0.96, stability: 0.4 | | Adhya (default) | Female | `20954ee135f2` | Warm voice with a personal and reassuring quality. | similarity: 0.75, speed: 1, stability: 0.5 | | Anika | Female | `1f2dca57a190` | Precise voice with calm authority and a clear delivery. | similarity: 0.75, speed: 1, stability: 0.5 | | Karan | Male | `a6d176ebfa69` | Natural voice with a cooperative and engaging quality. | similarity: 0.75, speed: 1, stability: 0.5 | | Krishna | Male | `8bc5db4e7b8a` | Casual and professional voice suitable for customer service. | similarity: 0.75, speed: 1, stability: 0.8 | | Monika | Female | `80261d110a91` | Ideal for vehicle support or general service follow-ups and customer interaction flows. | similarity: 0.75, speed: 1, stability: 0.8 | | Raju | Male | `b3d4f56b342e` | Professional voice with a polite and precise delivery. | similarity: 0.75, speed: 0.9, stability: 0.7 | | Riya | Female | `e7f5b3510a6c` | Widely recognized voice with a professional and authoritative tone. | similarity: 0.5, speed: 0.94, stability: 0.7 | | Simran | Female | `2cddfa18986a` | Down to earth woman with a deeper and warm tone. | similarity: 0.75, speed: 1, stability: 0.8 | | Tara | Female | `84898373125f` | Conversational young woman with dynamic expression. | similarity: 0.75, speed: 1, stability: 0.8 | | Vikram | Male | `ab8122e31b32` | Calm and experienced male voice with a reassuring tone. | similarity: 0.75, speed: 1, stability: 0.8 | ## Indonesian - id_ID | Voice | Gender | Voice ID | Description | Default Parameter Values | | :------ | :----- | :------------- | :---------------------------------------------------------------------- | :----------------------------------------- | | Putri | Female | `377e6348e694` | Warm voice with a captivating storytelling quality and lively delivery. | similarity: 0.75, speed: 1, stability: 0.8 | | Zephlyn | Male | `2a5f9641159c` | Measured voice with a clear and steady delivery. | similarity: 0.75, speed: 1, stability: 0.8 | ## Italian - it | Voice | Gender | Voice ID | Description | Default Parameter Values | | :--------------- | :----- | :------------- | :------------------------------------------------------------ | :-------------------------------------------- | | Chiara | Female | `9cabfa524f61` | Smooth voice with emotional precision and impactful presence. | similarity: 0.5, speed: 1.08, stability: 0.8 | | Felice | Male | `028587ff5980` | Professional voice with a composed and mature quality. | similarity: 0.75, speed: 1, stability: 0.5 | | Giovanni | Male | `d84a59414b10` | Neutral voice with a direct and measured delivery. | similarity: 0.75, speed: 1, stability: 0.5 | | Giulia (default) | Female | `04c0407e1ee3` | Natural voice with a distinctive tone and confident delivery. | similarity: 0.75, speed: 1, stability: 0.5 | | Marco | Male | `1cc2467d0128` | Trustworthy voice with a clear and composed delivery. | similarity: 0.75, speed: 1, stability: 0.6 | | Raffaele | Male | `0e86f6d63886` | Polished voice with a composed and confident quality. | similarity: 0.75, speed: 1, stability: 0.6 | | Tiziana | Female | `83908411926a` | Versatile voice with an intelligent and well-rounded quality. | similarity: 0.75, speed: 0.88, stability: 0.8 | | Violetta | Female | `de4a1bff7f05` | Clear voice with an expressive and informative quality. | similarity: 0.75, speed: 0.96, stability: 0.5 | ## Korean - ko_KR | Voice | Gender | Voice ID | Description | Default Parameter Values | | :-------------- | :----- | :------------- | :-------------------------------------------------------------- | :----------------------------------------- | | Han | Female | `fde18086bda5` | Free-flowing voice with an unscripted and approachable quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Harry (default) | Male | `4d80dac2983e` | Steady voice with a free-flowing and unscripted quality. | similarity: 0.75, speed: 1, stability: 0.8 | ## Malay - ms_MY | Voice | Gender | Voice ID | Description | Default Parameter Values | | :----- | :----- | :------------- | :---------------------------------------------------------------------- | :----------------------------------------- | | Aisyah | Female | `064da5af51f6` | Welcoming voice that bridges emotional depth with clarity and openness. | similarity: 0.75, speed: 1, stability: 0.8 | | Rizq | Male | `bcbd7beb799f` | Casual voice with a fresh and approachable quality. | similarity: 0.75, speed: 1, stability: 0.8 | ## Norwegian (Bokmål) - nb_NO | Voice | Gender | Voice ID | Description | Default Parameter Values | | :---- | :----- | :------------- | :------------------------------------------------------------------ | :----------------------------------------- | | Helge | Male | `46ec06801137` | Higher-toned voice with a natural and composed quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Maja | Female | `4c3f6b0c9124` | Deep voice with a distinct Norwegian cadence and immersive quality. | similarity: 0.75, speed: 1, stability: 0.8 | ## Polish - pl_PL | Voice | Gender | Voice ID | Description | Default Parameter Values | | :-------------- | :----- | :------------- | :------------------------------------------------------- | :----------------------------------------- | | Aleksandra | Female | `edeedbdf3e27` | Dynamic voice with a professional and versatile quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Kamil (default) | Male | `4845ec6b1395` | Warm voice with an energetic and supportive quality. | similarity: 0.75, speed: 1, stability: 0.8 | ## Portuguese (Brazil) - pt_BR | Voice | Gender | Voice ID | Description | Default Parameter Values | | :--------------- | :----- | :------------- | :----------------------------------------------------------------------- | :-------------------------------------------- | | Fernanda | Female | `51573e924e4f` | Welcoming voice that combines empathy and composed professionalism. | similarity: 0.75, speed: 1, stability: 0.8 | | Jose | Male | `3c33c3613029` | Voice with a distinctive São Paulo countryside accent and character. | similarity: 0.75, speed: 1, stability: 0.8 | | Mariana | Female | `7bce2aca39b9` | Upbeat voice with a professional yet approachable delivery. | similarity: 0.5, speed: 1, stability: 0.45 | | Racquel | Female | `0479ce05d9ef` | Strong voice with warmth and an explanatory tone. | similarity: 0.75, speed: 1, stability: 0.8 | | Roberta | Female | `f0aed380ce5e` | Warm voice with a clear and conversational quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Thiago (default) | Male | `783560f2adaf` | Smooth voice with formal reassuring intonation and precise articulation. | similarity: 0.75, speed: 0.94, stability: 0.5 | ## Portuguese (Portugal) - pt_PT | Voice | Gender | Voice ID | Description | Default Parameter Values | | :-------------- | :----- | :------------- | :------------------------------------------------------ | :--------------------------------------------- | | Beatriz | Female | `86344e190b6e` | Natural voice with a composed and approachable quality. | similarity: 0.75, speed: 0.95, stability: 0.45 | | Francisco | Male | `2e21c5f5bf64` | Confident voice with a resonant but measured tone. | similarity: 0.35, speed: 1, stability: 0.5 | | Tiago (default) | Male | `4c31112a4cbc` | Voice with a composed and informative delivery. | similarity: 0.75, speed: 1, stability: 0.8 | ## Romanian - ro_RO | Voice | Gender | Voice ID | Description | Default Parameter Values | | :----- | :----- | :------------- | :-------------------------------------------------------------- | :----------------------------------------- | | Anca | Female | `76cb2d4ebc16` | Naturally soothing voice with a soft accent and clear delivery. | similarity: 0.75, speed: 1, stability: 0.8 | | Robert | Male | `8c2827adb482` | Friendly voice with a clear and approachable quality. | similarity: 0.75, speed: 1, stability: 0.8 | ## Spanish (Latin America) - es_MX | Voice | Gender | Voice ID | Description | Default Parameter Values | | :------------- | :----- | :------------- | :--------------------------------------------------------------------------------------------------------------- | :--------------------------------------------- | | Agustín | Male | `815d6b4d087d` | Argentinian male voice with a natural and conversational tone. | similarity: 0.75, speed: 1, stability: 0.8 | | Alejandro | Male | `332a917866a9` | Clear Latin American voice with a warm tone and confident cadence. | similarity: 0.75, speed: 1, stability: 0.8 | | Alisson | Female | `8c0d04544636` | Colombian female voice with a natural and medium pitch that's warm and friendly. | similarity: 0.75, speed: 1, stability: 0.8 | | Andrea | Female | `adcf40fa2b0e` | Steady and balanced tone ideal for educational narration or podcasts. | similarity: 0.75, speed: 1, stability: 0.8 | | Antonio | Male | `083d06f58c86` | Warm voice with a subtle Latin accent and relatable tone. | similarity: 0.75, speed: 1, stability: 0.8 | | Carlos | Male | `ff0f3b6f2dda` | Clear voice with a defined timbre and professional sound. | similarity: 0.75, speed: 1, stability: 0.8 | | Carolina | Female | `cc57ad90275a` | Natural voice with a conversational and enthusiastic quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Cristian | Male | `a8157fbfb6b9` | Native Chilean Spanish voice perfect for social media. | similarity: 0.75, speed: 1, stability: 0.8 | | Enrique | Male | `b6562673d38b` | Mexican Spanish voice with a composed and clear delivery. | similarity: 0.75, speed: 1, stability: 0.8 | | Gaby | Female | `755899f9427c` | Young Peruvian woman with an expressive and vibrant voice. | similarity: 0.75, speed: 1, stability: 0.8 | | Horacio | Male | `2662fe03ebd7` | Clear and balanced voice ideal for transmitting important messages with a perfect mix of security and closeness. | similarity: 0.75, speed: 1, stability: 0.8 | | Jehison | Male | `4782cd047073` | Young Peruvian man from Lima with a medium pitch and a casual pace. | similarity: 0.75, speed: 1, stability: 0.8 | | Jhenny | Female | `00094ae4aa4d` | Melodious Latin American voice with a fluid and versatile quality. | similarity: 0.75, speed: 1, stability: 0.8 | | José (default) | Male | `1c69047a1dac` | Warm voice with a culturally rich Mexican accent and authoritative presence. | similarity: 0.75, speed: 0.94, stability: 0.5 | | Juan Carlos | Male | `0a4934dfb005` | Warm voice with an engaging and composed delivery. | similarity: 0.75, speed: 1, stability: 0.8 | | Karla | Female | `02fd3a316d30` | Dynamic voice perfect for conversations with clients. | similarity: 0.75, speed: 1, stability: 0.8 | | Norah | Female | `fa7a7b0e1fff` | Clear Latin American voice with a neutral accent and approachable tone. | similarity: 0.75, speed: 1, stability: 0.8 | | Regina | Female | `33575d793326` | Deep voice with a composed and dignified quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Sofi | Female | `5c1229777ba7` | Soft Medellín accent that's designed to connect with Latin American audiences. | similarity: 0.75, speed: 1, stability: 0.8 | | Sofía | Female | `7a7d6cef0f24` | Charming Latin American voice that brings warmth and cultural richness. | similarity: 0.75, speed: 0.94, stability: 0.45 | | Vicky | Female | `ae09dd86dbe2` | Calm and natural voice with a hint of rasp which is great for casual conversations. | similarity: 0.75, speed: 1, stability: 0.8 | ## Spanish (Spain) - es | Voice | Gender | Voice ID | Description | Default Parameter Values | | :--------------- | :----- | :------------- | :------------------------------------------------------------- | :----------------------------------------- | | Alegria | Female | `1afdf5771ac4` | Mature voice optimal for providing certainty in conversations. | similarity: 0.75, speed: 1, stability: 0.8 | | Dani | Male | `4f5152998917` | Youthful voice with an easygoing and approachable quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Garbiela | Female | `28bedfc5984b` | Clear voice with an approachable and measured quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Jesus | Male | `73f07cd54d0a` | Deep Castilian voice with a firm and authoritative tone. | similarity: 0.75, speed: 1, stability: 0.8 | | Raquel (default) | Female | `3b7b09534aa5` | Youthful voice with a clear and conversational quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Tony | Male | `65b371445cee` | Warm voice with a natural and easygoing delivery. | similarity: 0.75, speed: 1, stability: 0.8 | ## Swedish - sv_SE | Voice | Gender | Voice ID | Description | Default Parameter Values | | :--------------- | :----- | :------------- | :------------------------------------------------- | :----------------------------------------- | | Annie | Female | `e6a62adae256` | Calm voice with a composed and dignified quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Petter (default) | Male | `f170120495e0` | Versatile voice with a clear and engaging quality. | similarity: 0.75, speed: 1, stability: 0.8 | ## Turkish - tr_TR | Voice | Gender | Voice ID | Description | Default Parameter Values | | :-------------- | :----- | :------------- | :---------------------------------------------------- | :----------------------------------------- | | Ecem | Female | `b3fc3e62b65a` | Sincere voice with a balanced and expressive quality. | similarity: 0.75, speed: 1, stability: 0.8 | | Harun (default) | Male | `8b7708dfdffc` | Modern voice with a steady and contemporary quality. | similarity: 0.75, speed: 1, stability: 0.8 | ## Related Topics - [Voice Catalog for Agentforce Voice](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice-catalog.md) - [Configure Voice Models in Agent Script](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice.md) - [ElevenLabs](https://elevenlabs.io/) # ElevenLabs v3 Conversational Voices This page lists the ElevenLabs v3 Conversational voice personas and the locales each one supports. ElevenLabs v3 Conversational is the default voice model, so you don't have to set a `persona_id` to use it — each locale falls back to the voice marked **(default)**. Set a `persona_id` only when you want a specific voice. For how to select a model and configure a voice, see [Configure Voice Models in Agent Script](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice.md). ElevenLabs v3 Conversational voices don't use the `speed` or `similarity` parameters, and `stability` defaults to 0.5. ## Arabic (Egypt) - ar_EG | Voice | Gender | Voice ID | Description | | :------ | :----- | :------------- | :------------------------------------------------------------------------- | | Amir | Male | `f60b089412f0` | Rich Egyptian voice with clarity and wide emotional range. | | Hoda | Female | `51a659d6b3cd` | Distinctive Egyptian voice with an expressive and captivating quality. | | Omar | Male | `fea79f8655b6` | Confident voice with a clear Egyptian accent and professional tone. | | Yasmine | Female | `b8e6c91d2c1a` | Natural Egyptian voice with an effortlessly conversational and human tone. | ## Arabic (Saudi Arabia) - ar_SA | Voice | Gender | Voice ID | Description | | :---- | :----- | :------------- | :---------------------------------------------------------------- | | Ali | Male | `6990347da30a` | Calm voice with a resonant and balanced professional delivery. | | Heba | Female | `0c860bc624ee` | Calm voice with a trustworthy and emotionally grounded quality. | | Layan | Female | `38d0d2ef5f86` | Professional voice with a subtle Najdi quality and composed tone. | | Saud | Male | `838dbf2af6d5` | Deep voice with a formal and trustworthy Saudi delivery. | ## Arabic (U.A.E.) - ar_AE | Voice | Gender | Voice ID | Description | | :----- | :----- | :------------- | :-------------------------------------------------------------- | | Amira | Female | `64661add53cc` | Composed voice with a smooth Gulf accent and dignified tone. | | Latifa | Female | `2643f97e39cc` | Resonant voice with a rich Gulf accent and reassuring presence. | | Rashid | Male | `f0f70a02c21d` | Narrative voice with a close and present storytelling quality. | | Sultan | Male | `fcb270d28094` | Clear Emirati voice with a confident and natural delivery. | ## Chinese (Simplified) - zh_CH | Voice | Gender | Voice ID | Description | | :----- | :----- | :------------- | :------------------------------------------------------------- | | Amy | Female | `588c28067cef` | Natural voice with a relaxed and friendly conversational tone. | | Haoran | Male | `c44fb5a7833e` | Deep voice with a steady tone and expressive delivery. | | Sage | Female | `b787f692bdad` | Soothing voice with a calm and gently intimate quality. | | Siqi | Male | `5349e0d48d99` | Warm voice with a gentle rhythm and natural articulation. | | Wei | Male | `69e5693f04bc` | Friendly voice with a calm and conversational delivery. | ## Chinese (Traditional) - zh_TW | Voice | Gender | Voice ID | Description | | :---- | :----- | :------------- | :----------------------------------------------------------- | | Anna | Female | `96e1c5837cc0` | Bright voice with a youthful and effortlessly engaging tone. | ## Croatian - hr_HR | Voice | Gender | Voice ID | Description | | :---- | :----- | :------------- | :---------------------------------------------------- | | Karlo | Male | `77c5a2b997f1` | Pleasant voice with a natural and easygoing delivery. | | Luka | Male | `366739ca4103` | Neutral voice with a steady and composed quality. | ## Czech - cs_CZ | Voice | Gender | Voice ID | Description | | :------ | :----- | :------------- | :--------------------------------------------------------------- | | Antonín | Male | `1073063deade` | Velvety voice with a natural and approachable quality. | | Iveta | Female | `89f6844cf424` | Reflective voice with gentle articulation and a reassuring tone. | ## Danish - da_DK | Voice | Gender | Voice ID | Description | | :---- | :----- | :------------- | :------------------------------------------------------ | | Klara | Female | `2169fc7b6b52` | Gentle voice that conveys reassurance with a warm tone. | | Peder | Male | `51d982635aa5` | Measured voice with a steady and informative delivery. | ## Dutch - nl | Voice | Gender | Voice ID | Description | | :------ | :----- | :------------- | :------------------------------------------------------------------ | | James | Male | `8804311f0892` | Native Dutch voice with a full and authoritative quality. | | Jann | Male | `e108ce1c70e1` | Warm voice with a natural calmness and clear delivery. | | Lara | Female | `226f834c4c86` | Enthusiastic Flemish/Dutch voice with a crisp and composed quality. | | Melanie | Female | `f4dce512ca06` | Clear voice with a youthful and engaging quality. | | Pieter | Male | `e0da093caf89` | Reliable voice with a warm and informative quality. | | Ruth | Female | `0360601f937f` | Recognizable voice in a casual register. | ## English (Australia) - en_AU | Voice | Gender | Voice ID | Description | | :----- | :----- | :------------- | :---------------------------------------------------------------------------------------------------------------------- | | David | Male | `9bf993a97e93` | Upbeat male voice with a bright Australian accent a confident casual pace and a lively friendly energy | | Emma | Female | `a05683132f08` | Clear lively female voice with a soft Australian accent a friendly relaxed cadence and a fresh sunny energy | | Jack | Male | `39c48d562548` | Articulate and well-modulated voice with a professional tone. | | Jason | Male | `b6645999447e` | Relaxed male voice with an easygoing Australian accent a laid-back sunny delivery and a genuine down-to-earth warmth | | Louise | Female | `4146fdd15a52` | Bright cheerful female voice with a breezy Australian accent a playful natural delivery and a warm inviting charm | | Marty | Male | `0e889fa94186` | Warm grounded male voice with a broad Australian accent a steady confident delivery and a rugged approachable character | ## English (United Kingdom) - en_GB | Voice | Gender | Voice ID | Description | | :-------- | :----- | :------------- | :---------------------------------------------------------------------------------------------------------------------- | | Charlotte | Female | `d1eda722852f` | Elegant female voice with a smooth RP tone a confident poised delivery and a warm sophisticated character | | Elliot | Male | `75b95fcf5663` | Bright energetic male voice with a clean RP accent a lively fresh delivery and an easygoing modern feel | | Hugh | Male | `2779d878998b` | Warm mature male voice with a rounded RP tone an assured steady delivery and a reassuring professional presence | | Isla | Female | `9a542d497a67` | Gentle voice with a smooth and slightly airy timbre. | | Joanna | Female | `9fe7ff92579a` | Clear expressive female voice with a soft RP tone a friendly upbeat cadence and an effortless conversational style | | Joe | Male | `6585246099d2` | Rich resonant male voice with a classic RP clarity a composed measured rhythm and a dignified commanding quality | | Lucy | Female | `a6ead9824bc3` | Graceful mature female voice with crisp RP diction a calm measured pace and a gentle authoritative warmth | | Noah | Male | `7e04c8f923d0` | Smooth voice with a slightly higher timbre that's clear and informative. | | Oliver | Male | `7bdf6b47a1e2` | Deep refined male voice with crisp RP articulation a measured authoritative pace and a distinguished polished character | | Ophelia | Female | `cb03e2b12b23` | Light bright female voice with a polished RP accent a cheerful natural delivery and an approachable youthful charm | ## English (United States) - en_US | Voice | Gender | Voice ID | Description | | :-------- | :----- | :------------- | :------------------------------------------------------------------------------------------------ | | Adam | Male | `0fb8843fee36` | Friendly and neutral young American voice with an authentic conversational pace. | | Alex | Male | `9f23c073628d` | Bold voice with infectious energy and flair. | | April | Female | `84d16ca5604f` | Voice that reads numbers naturally and with even delivery. | | Asher | Male | `bd65422ea05e` | Warm voice that communicates with ease and sincerity. | | Bella | Female | `88afc8096500` | Warm and professional with a standard American accent. Polished and easy to listen to. | | Brady | Male | `216811b84e3a` | Friendly voice that builds trust and communicates with clarity. | | Burt | Male | `db3344284411` | Smooth voice that guides listeners with clarity and depth. | | Cassidy | Female | `4369d4fe6865` | Confident voice with a composed and assured quality. | | Chad | Male | `82e3d851ac98` | Voice with a slightly textured quality and a youthful edge. | | Chris | Male | `3c7526602719` | Smooth voice with a relaxed and effortless quality. | | Christina | Female | `8c264ec49879` | Accessible voice with an approachable quality. | | Clara | Female | `14864ab7785f` | Bright voice with clarity and a cooperative quality. | | Cliff | Male | `aef1ee11f3f2` | Extremely natural voice with neutral emotion and measured delivery. | | Fiona | Female | `31eda511aca2` | Voice with a lower pitch and a natural cadence. | | Gregg | Male | `39252f6b14db` | No-nonsense voice with an honest and composed quality. | | Heath | Female | `e4dd2d57dcb2` | Straightforward voice with a direct and collegial tone. | | Heather | Female | `a51fe7b90675` | Even-keeled voice with an unpretentious and understated quality. | | Hoku | Female | `96fb43377768` | Upbeat female voice with a warm Hawaiian lilt and youthful local charm. | | Hope | Female | `0cb263833f4a` | Youthful voice with a warm and conversational quality. | | Jahmal | Male | `dc7bc13400ac` | Energetic voice with infectious enthusiasm and dynamic presence. | | Jalisa | Female | `e40c1b68ef8c` | Voice with precise articulation and a measured tone. | | Jerry | Male | `42c6e831efe1` | Clear and easygoing voice with a natural conversational quality. | | Jessica | Female | `44887ff81913` | Articulate voice with a cooperative and clear delivery. | | Josh | Male | `1f6c130e74ca` | Relaxed voice with a natural and unforced quality. | | Juniper | Female | `a405ae761965` | Warm female voice with a smooth American accent and a confident delivery. | | Kai | Female | `d6c8dce1b4a3` | Gentle Southern voice with a measured and composed tone. | | Kris | Male | `d8b0d819ea28` | Deep voice with studio-quality sound and a professional demeanor. | | Kyle | Male | `8a3da48657fd` | Voice that delivers numbers and names with consistent precision. | | Laura | Female | `fdc11c6367b5` | Enthusiastic voice with charm and a quirky personality. | | Lemania | Female | `763bc09a25fc` | Soulful Southern drawl with a deeply reassuring quality. | | Lisa | Female | `bb4c82fc4bd7` | Relaxed voice with a natural human touch. | | Liz | Female | `1dbf9abaf3f5` | Bright voice with lifelike energy and warmth. | | Marcus | Male | `9d763a0790da` | New England-accented voice with a distinctive regional character. | | Marisa | Female | `081469f2da25` | A young adult woman with a youthful and natural voice perfect for conversations with a friend. | | Mark | Male | `2fe6f51ff3f1` | Casual voice with an easygoing and approachable quality. | | Olivia | Female | `dd0c9186f164` | Calm British voice with a slightly lower pitch and smooth timbre. | | Pete | Male | `89000894f133` | Approachable voice with a friendly and explanatory quality. | | Siren | Female | `2461958846ba` | Neutral and realistic young American voice with a natural conversational pace and clear delivery. | | Tessa | Female | `82eb49b015d9` | Voice with youthful ease and an effortless quality. | | Todd | Male | `62c43add037c` | Conversational voice with a natural and composed delivery. | | Victoria | Female | `2049b88c7209` | Heartfelt voice with a casual and relatable quality. | | Will | Male | `f9d9c9d2f8ab` | Distinctive voice with relaxed energy and an easygoing quality. | ## Filipino - fil_PH | Voice | Gender | Voice ID | Description | | :------ | :----- | :------------- | :----------------------------------------------------------------- | | Avelina | Female | `55061db6b487` | Graceful voice that conveys sincerity and composed authority. | | Pocholo | Male | `f9136dfd445e` | Warm voice with a storytelling quality that inspires and connects. | ## Finnish - fi_FI | Voice | Gender | Voice ID | Description | | :----- | :----- | :------------- | :------------------------------------------------------------------- | | Jussi | Male | `fab1611c3d25` | Distinctively accented voice with a light-hearted and humorous tone. | | Martti | Male | `50eede2690e8` | Deep male voice with a clear Finnish accent and a calm delivery. | | Miika | Male | `be2f907f3b75` | Warm male voice with a smooth Finnish accent and a composed pace. | | Viisas | Male | `c073abb77ed1` | Clear voice that sounds trustworthy and authoritative. | ## French (Canada) - fr_CA | Voice | Gender | Voice ID | Description | | :----------- | :----- | :------------- | :------------------------------------------------------------------------------------------------------------------------- | | Amélie | Female | `de2b6f6a8abb` | Credible voice with a clear Quebec accent and precise articulation. | | Gabrielle | Female | `4c5d9f8464ab` | Soft voice with a clear Quebec accent and a smooth tone. | | Haseeb | Male | `2fd0a21210f5` | Informative voice with a clear and instructive quality. | | Jeanne | Female | `6a4c1b5d7c40` | Warm voice with a patient and instructive quality. | | Louis Boutin | Male | `3def0deebb9a` | Authentic French Canadian voice with a native Quebec accent. Well-suited for training videos with a warm Quebecois flavor. | | Léo | Male | `2c46b7c5ddfa` | Reassuring voice with a smiling tone and an uplifting quality. | | Marie | Female | `f3894a884ea3` | Calm voice that inspires confidence with a smiling quality. | | Mathieu | Male | `1368215148d9` | Clear voice with a calming and reassuring tone. | ## French (France) - fr | Voice | Gender | Voice ID | Description | | :------- | :----- | :------------- | :--------------------------------------------------------------- | | Hugues | Male | `955bc0831bdb` | Warm voice with a confident lower-mid resonance. | | Jade | Female | `cca36edc146d` | Instructional and easy to follow. Perfect for customer support. | | Koraly | Female | `4d8d3d371fb6` | Expressive voice that adapts naturally to varied content. | | Louis | Male | `61af303a3a5a` | Pleasing voice that is smooth and somewhat deep. | | Lucie | Female | `047eb41e64d9` | Realistic voice with a natural and approachable tone. | | Marcel | Male | `64add1f05432` | Conversational voice with an approachable and easygoing quality. | | Sophie | Female | `78071b7931a8` | Soft voice with a precise European accent and gentle tone. | | Theo | Male | `3fe30e769cc3` | Optimistic voice with an upbeat and engaging quality. | | Victoire | Female | `03748a5de029` | Fluid voice with exceptional clarity and engaging presence. | ## German - de | Voice | Gender | Voice ID | Description | | :------ | :----- | :------------- | :----------------------------------------------------------------------------- | | Anton | Male | `43c202942ad3` | Calm voice with a deliberate and conversational delivery. | | Ben | Male | `6257de753ecc` | Versatile voice that switches effortlessly from upbeat to warm and reassuring. | | Ela | Female | `3a380893c8bd` | Curious voice with natural sparkle and a lively quality. | | Felix | Male | `e43c7da52fdd` | Clear voice with neutral pronunciation and a consistent delivery. | | Frieda | Female | `db920ffef4a3` | Natural voice with a medium pitch and conversational delivery. | | Irene | Female | `19e815d2b3ac` | Warm voice with soft intonation and a slightly humorous tone. | | Julia | Female | `e692e6eabdd7` | Calm voice with a composed and reliable delivery. | | Marc | Male | `aceb3ce9b42a` | Highly pleasant voice with a smooth and sustained delivery. | | Rebecca | Female | `5c66721a4a6c` | Clear voice that builds trust and explains complex topics with ease. | | Simon | Male | `1a777004861d` | Youthful voice with natural pauses and a thoughtful delivery. | ## Greek - el_GR | Voice | Gender | Voice ID | Description | | :------- | :----- | :------------- | :------------------------------------------------------- | | Georgios | Male | `fb11640a5dda` | Measured voice with a naturally conversational delivery. | | Marta | Female | `bd1a134d9c20` | Versatile voice with a clear and dynamic delivery. | ## Hindi - hi | Voice | Gender | Voice ID | Description | | :------ | :----- | :------------- | :-------------------------------------------------------------------------------------- | | Aakash | Male | `8ac9fefe9c15` | Widely recognized voice with a supportive and composed tone. | | Adhya | Female | `5bb4d484bf9c` | Warm voice with a personal and reassuring quality. | | Anika | Female | `d3455c0771b3` | Precise voice with calm authority and a clear delivery. | | Karan | Male | `35b10f124b48` | Natural voice with a cooperative and engaging quality. | | Krishna | Male | `4c6cbc1218df` | Casual and professional voice suitable for customer service. | | Monika | Female | `7aa7760df9f8` | Ideal for vehicle support or general service follow-ups and customer interaction flows. | | Raju | Male | `f9f142822484` | Professional voice with a polite and precise delivery. | | Riya | Female | `37934b24b122` | Widely recognized voice with a professional and authoritative tone. | | Simran | Female | `e29cea947f4f` | Down to earth woman with a deeper and warm tone. | | Tara | Female | `533051cd1bb3` | Conversational young woman with dynamic expression. | | Vikram | Male | `d07c0c697918` | Calm and experienced male voice with a reassuring tone. | ## Indonesian - id_ID | Voice | Gender | Voice ID | Description | | :------ | :----- | :------------- | :---------------------------------------------------------------------- | | Putri | Female | `dc16d5d89303` | Warm voice with a captivating storytelling quality and lively delivery. | | Zephlyn | Male | `4ac662bf637e` | Measured voice with a clear and steady delivery. | ## Italian - it | Voice | Gender | Voice ID | Description | | :------- | :----- | :------------- | :------------------------------------------------------------ | | Chiara | Female | `e45e483db99d` | Smooth voice with emotional precision and impactful presence. | | Felice | Male | `ae58a7a8bc7b` | Professional voice with a composed and mature quality. | | Giovanni | Male | `ca851e6796e8` | Neutral voice with a direct and measured delivery. | | Giulia | Female | `86e7fffa43b7` | Natural voice with a distinctive tone and confident delivery. | | Marco | Male | `8c04e24b24c7` | Trustworthy voice with a clear and composed delivery. | | Raffaele | Male | `a7ecbc1f7342` | Polished voice with a composed and confident quality. | | Tiziana | Female | `14c268689318` | Versatile voice with an intelligent and well-rounded quality. | | Violetta | Female | `9c0cd4cf4bcc` | Clear voice with an expressive and informative quality. | ## Korean - ko_KR | Voice | Gender | Voice ID | Description | | :---- | :----- | :------------- | :-------------------------------------------------------------- | | Han | Female | `671345888ef6` | Free-flowing voice with an unscripted and approachable quality. | | Harry | Male | `9610b0c3961e` | Steady voice with a free-flowing and unscripted quality. | ## Malay - ms_MY | Voice | Gender | Voice ID | Description | | :------ | :----- | :------------- | :----------------------------------------------------------------------------------------------------------------- | | Aina | Female | `e6061f2e5da3` | Young female Malay voice that is soft and approachable. Ideal for everyday conversations and interactive IVRs. | | Aisyah | Female | `e4917ab986d4` | Warm and clear Malay voice with a polite tone. Ideal for customer care and IVR flows. | | Ashraf | Male | `9dbb5a61ad7b` | Smooth and expressive Malay voice that sounds like a real person. Ideal for social media and creator-led videos. | | Hasnan | Male | `8ad1c300af74` | Great for conversation. | | Rizq | Male | `b2caf2e10dc1` | Casual voice with a fresh and approachable quality. | | Syalala | Female | `82a586292d17` | Female voice in her mid-30s with a natural Malaysian Malay accent. Warm and engaging voice ideal for storytelling. | ## Norwegian (Bokmål) - nb_NO | Voice | Gender | Voice ID | Description | | :---- | :----- | :------------- | :------------------------------------------------------------------ | | Helge | Male | `866d360d8f0e` | Higher-toned voice with a natural and composed quality. | | Maja | Female | `eb63f9a75d0a` | Deep voice with a distinct Norwegian cadence and immersive quality. | ## Polish - pl_PL | Voice | Gender | Voice ID | Description | | :--------- | :----- | :------------- | :------------------------------------------------------- | | Aleksandra | Female | `88e8ef4240d4` | Dynamic voice with a professional and versatile quality. | | Kamil | Male | `69e40f8a5547` | Warm voice with an energetic and supportive quality. | ## Portuguese (Brazil) - pt_BR | Voice | Gender | Voice ID | Description | | :------- | :----- | :------------- | :------------------------------------------------------------------- | | Fernanda | Female | `12a8bcc2aada` | Welcoming voice that combines empathy and composed professionalism. | | Jose | Male | `388e7d2beae0` | Voice with a distinctive São Paulo countryside accent and character. | | Mariana | Female | `5e1e6c32123b` | Upbeat voice with a professional yet approachable delivery. | | Racquel | Female | `a94a2b6ae79b` | Strong voice with warmth and an explanatory tone. | | Roberta | Female | `495da8792500` | Warm voice with a clear and conversational quality. | | Thiago | Male | `c4354415bf7a` | Smooth voice with reassuring intonation and precise articulation. | ## Portuguese (Portugal) - pt_PT | Voice | Gender | Voice ID | Description | | :-------- | :----- | :------------- | :------------------------------------------------------ | | Beatriz | Female | `1c2e20cb662d` | Natural voice with a composed and approachable quality. | | Francisco | Male | `106bbc013934` | Confident voice with a resonant but measured tone. | | Tiago | Male | `495dbd47e23e` | Voice with a composed and informative delivery. | ## Romanian - ro_RO | Voice | Gender | Voice ID | Description | | :----- | :----- | :------------- | :-------------------------------------------------------------- | | Anca | Female | `a9348e808c3d` | Naturally soothing voice with a soft accent and clear delivery. | | Robert | Male | `083dd0c1b00f` | Friendly voice with a clear and approachable quality. | ## Spanish (Latin America) - es_MX | Voice | Gender | Voice ID | Description | | :---------- | :----- | :------------- | :--------------------------------------------------------------------------------------------------------------- | | Agustín | Male | `6c81954effbd` | Argentinian male voice with a natural and conversational tone. | | Alejandro | Male | `9f9773c3c7ef` | Clear Latin American voice with a warm tone and confident cadence. | | Alisson | Female | `5cc515e96f54` | Colombian female voice with a natural and medium pitch that's warm and friendly. | | Andrea | Female | `730ddca9bec5` | Steady and balanced tone ideal for educational narration or podcasts. | | Antonio | Male | `bc68361f9676` | Warm voice with a subtle Latin accent and relatable tone. | | Carlos | Male | `ca70e9f56d8c` | Clear voice with a defined timbre and professional sound. | | Carolina | Female | `d5e493553260` | Natural voice with a conversational and enthusiastic quality. | | Cristian | Male | `9c5dd560bac3` | Native Chilean Spanish voice perfect for social media. | | Enrique | Male | `8a16d2e2e2da` | Mexican Spanish voice with a composed and clear delivery. | | Gaby | Female | `8b4ed6b4df47` | Young Peruvian woman with an expressive and vibrant voice. | | Horacio | Male | `666373431834` | Clear and balanced voice ideal for transmitting important messages with a perfect mix of security and closeness. | | Jehison | Male | `879f53678e38` | Young Peruvian man from Lima with a medium pitch and a casual pace. | | Jhenny | Female | `d0631fe2ce8f` | Melodious Latin American voice with a fluid and versatile quality. | | José | Male | `7d501952a948` | Warm voice with a culturally rich Mexican accent and authoritative presence. | | Juan Carlos | Male | `4c42c050f74b` | Warm voice with an engaging and composed delivery. | | Karla | Female | `038d79277a32` | Dynamic voice perfect for conversations with clients. | | Norah | Female | `e7124e35e3f5` | Clear Latin American voice with a neutral accent and approachable tone. | | Regina | Female | `3129d51bec0f` | Deep voice with a composed and dignified quality. | | Sofi | Female | `79fa12c8096b` | Soft Medellín accent that's designed to connect with Latin American audiences. | | Sofía | Female | `580dfb28c610` | Charming Latin American voice that brings warmth and cultural richness. | | Vicky | Female | `7c11ca0787e6` | Calm and natural voice with a hint of rasp which is great for casual conversations. | ## Spanish (Spain) - es | Voice | Gender | Voice ID | Description | | :------- | :----- | :------------- | :------------------------------------------------------------- | | Adriana | Female | `a1cab32407b7` | Young voice for conversations. | | Alegria | Female | `25b10f57a6a8` | Mature voice optimal for providing certainty in conversations. | | Dani | Male | `7f9f849879b8` | Youthful voice with an easygoing and approachable quality. | | Garbiela | Female | `a1c5f8f2d581` | Clear voice with an approachable and measured quality. | | Javier | Male | `f3552fa368cd` | 40 years old Spanish male with clear and calm voice. | | Jesus | Male | `61dfc615c620` | Deep Castilian voice with a firm and authoritative tone. | | Raquel | Female | `34a552d952c1` | Youthful voice with a clear and conversational quality. | | Tony | Male | `ab57cc31a42e` | Warm voice with a natural and easygoing delivery. | ## Swedish - sv_SE | Voice | Gender | Voice ID | Description | | :----- | :----- | :------------- | :------------------------------------------------- | | Annie | Female | `bbcb2533147d` | Calm voice with a composed and dignified quality. | | Petter | Male | `42987e5cac8d` | Versatile voice with a clear and engaging quality. | ## Turkish - tr_TR | Voice | Gender | Voice ID | Description | | :---- | :----- | :------------- | :---------------------------------------------------- | | Ecem | Female | `0270a641dd30` | Sincere voice with a balanced and expressive quality. | | Harun | Male | `bf03fb72afbd` | Modern voice with a steady and contemporary quality. | ## Related Topics - [Voice Catalog for Agentforce Voice](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice-catalog.md) - [Configure Voice Models in Agent Script](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice.md) - [ElevenLabs](https://elevenlabs.io/) # Employee Agent Authentication in React Native Learn how to authenticate users for Employee Agent mode using the Salesforce Mobile SDK integration or direct tokens. ## Overview Employee Agent authentication supports two approaches: ### Bridge Auth (via Mobile SDK) The Salesforce Mobile SDK handles the OAuth login flow natively. This is the recommended approach for production apps. ``` JS calls loginForEmployeeAgent() → EmployeeAgentAuthBridge.login() → SalesforceSDKManager shows OAuth login screen → User logs in → Returns AuthCredentials to JS → JS passes credentials to AgentforceService.configure() ``` ### Direct Token You provide an OAuth `accessToken` directly in the `EmployeeAgentConfig`. This is useful for development, testing, or when your app manages its own auth flow. ## Mobile SDK Integration To use the Mobile SDK for authentication, configure your project for each platform. ### iOS Setup Use the `WithMobileSDK` subspec in your Podfile: ```ruby pod 'ReactNativeAgentforce/WithMobileSDK', :path => '../node_modules/@salesforce/react-native-agentforce/ios' ``` This adds a dependency on `SalesforceSDKCore`, which provides OAuth login/logout flows, user account management, and token storage and refresh. ### Android Setup Add `SalesforceReact` as a runtime dependency in your `android/app/build.gradle`: ```gradle dependencies { implementation "com.salesforce.mobilesdk:SalesforceReact:13.1.1" } ``` The bridge library declares `SalesforceReact` as `compileOnly`. Your host app must provide the dependency at runtime. `AgentforcePackage` uses reflection to detect if `SalesforceSDKManager` is on the classpath. If found, `EmployeeAgentAuthBridge` is registered as a native module. If not, Employee Agent auth is gracefully disabled. ## Auth Functions All auth functions are exported directly from the package: ```tsx import { isEmployeeAgentAuthSupported, isEmployeeAgentAuthReady, hasEmployeeAgentSession, loginForEmployeeAgent, logoutEmployeeAgent, getEmployeeAgentCredentials, refreshEmployeeAgentCredentials, } from "@salesforce/react-native-agentforce"; ``` ### isEmployeeAgentAuthSupported() Returns `true` if the build includes Mobile SDK and the `EmployeeAgentAuthBridge` native module is available. Use this to conditionally show/hide Employee Agent UI in your app. ```tsx const supported = await isEmployeeAgentAuthSupported(); ``` ### hasEmployeeAgentSession() Returns `true` if the user is currently logged in with valid credentials. ```tsx const loggedIn = await hasEmployeeAgentSession(); ``` ### loginForEmployeeAgent() Launches the Mobile SDK's OAuth login flow. Returns `AuthCredentials` on success. ```tsx try { const creds = await loginForEmployeeAgent(); console.log("Logged in:", creds.userId); } catch (error) { // User cancelled, auth bridge unavailable, or login failed console.error("Login failed:", error); } ``` ### logoutEmployeeAgent() Logs out the current user via Mobile SDK. Clears stored credentials and tokens. ```tsx await logoutEmployeeAgent(); ``` ### getEmployeeAgentCredentials() Returns the current auth credentials if the user is logged in, or `null` if no session exists. ```tsx const creds = await getEmployeeAgentCredentials(); if (creds) { console.log(`Logged in as ${creds.userId}`); } ``` ### refreshEmployeeAgentCredentials() Asks the Mobile SDK to refresh the current session and returns new credentials. ```tsx const newCreds = await refreshEmployeeAgentCredentials(); ``` ### AuthCredentials Interface ```tsx interface AuthCredentials { instanceUrl: string; // Salesforce instance URL organizationId: string; // Org ID userId: string; // User ID accessToken: string; // Current OAuth access token refreshToken?: string; // Refresh token (may not be available on all platforms) } ``` ## Complete Login Flow Here's a complete login flow for Employee Agent with Mobile SDK: ```tsx import { AgentforceService, isEmployeeAgentAuthSupported, hasEmployeeAgentSession, loginForEmployeeAgent, getEmployeeAgentCredentials, } from "@salesforce/react-native-agentforce"; async function launchEmployeeAgent(agentId?: string) { // Step 1: Check if auth bridge is available const authSupported = await isEmployeeAgentAuthSupported(); if (!authSupported) { throw new Error("Employee Agent auth is not available in this build."); } // Step 2: Check for existing session, or login let creds = await getEmployeeAgentCredentials(); if (!creds) { creds = await loginForEmployeeAgent(); } // Step 3: Get stored agent ID (or use provided one) const resolvedAgentId = agentId || (await AgentforceService.getEmployeeAgentId()); // Step 4: Configure Employee Agent await AgentforceService.configure({ type: "employee", instanceUrl: creds.instanceUrl, organizationId: creds.organizationId, userId: creds.userId, agentId: resolvedAgentId || undefined, accessToken: creds.accessToken, }); // Step 5: Launch conversation await AgentforceService.launchConversation(); } ``` ## Token Refresh The SDK supports both automatic and manual token refresh. ### Automatic Refresh The native SDK automatically fetches fresh tokens from the Mobile SDK when the current token expires. The `UnifiedCredentialProvider` on both platforms integrates with the Mobile SDK's user account system. ### Manual Refresh For scenarios where you need explicit control: ```tsx try { const newCreds = await refreshEmployeeAgentCredentials(); console.log("New access token:", newCreds.accessToken); // Optionally reconfigure with new token await AgentforceService.configure({ type: "employee", instanceUrl: newCreds.instanceUrl, organizationId: newCreds.organizationId, userId: newCreds.userId, accessToken: newCreds.accessToken, }); } catch (error) { // Token refresh failed -- may need to re-login console.error("Refresh failed:", error); } ``` ## Direct Token Mode If you don't want to integrate the Mobile SDK but still need Employee Agent functionality, you can provide tokens directly: ```tsx // Obtain token through your own auth mechanism const token = await myAuthService.getAccessToken(); await AgentforceService.configure({ type: "employee", instanceUrl: "https://myorg.my.salesforce.com", organizationId: "00Dxx0000001234", userId: "005xx0000001234", agentId: "0Xxxx0000001234", accessToken: token, }); await AgentforceService.launchConversation(); ``` In this mode: - `isEmployeeAgentAuthSupported()` returns `false`. - You're responsible for obtaining, storing, and refreshing tokens. - The native SDK won't automatically refresh the token. - When the token expires, the conversation may fail. You'll need to obtain a new token and call `configure()` again. ## Local Config Override File For development and testing, you can create a local configuration file that contains your Employee Agent settings and is not committed to source control. Create `src/config/employeeAgentConfig.local.ts`: ```tsx import type { EmployeeAgentConfig } from "@salesforce/react-native-agentforce"; export const EMPLOYEE_AGENT_ENABLED = true; export const EMPLOYEE_AGENT_CONFIG: EmployeeAgentConfig = { type: "employee", instanceUrl: "https://my-dev-org.my.salesforce.com", organizationId: "00Dxx0000001234", userId: "005xx0000001234", accessToken: "dev_access_token_here", }; export function isEmployeeAgentConfigValid(): boolean { return ( !!EMPLOYEE_AGENT_CONFIG.instanceUrl && !!EMPLOYEE_AGENT_CONFIG.organizationId && !!EMPLOYEE_AGENT_CONFIG.userId ); } ``` The bridge package exports these constants and the validation function. If the local override file exists, its exports are used; otherwise, defaults are returned (`EMPLOYEE_AGENT_ENABLED: false`, empty config). Add the file to your `.gitignore`: ``` # Employee Agent local config (contains tokens) **/employeeAgentConfig.local.ts ``` For more details on these exports, see the Authentication Reference in the React Native SDK reference documentation. ## Session Management Use these functions to check and manage the user's authentication session. ### Checking Session State ```tsx // Is auth available in this build? const supported = await isEmployeeAgentAuthSupported(); // Is the user currently logged in? const loggedIn = await hasEmployeeAgentSession(); // Get full credentials (or null) const creds = await getEmployeeAgentCredentials(); ``` ### Logout ```tsx async function handleLogout() { // Close any active conversation await AgentforceService.closeConversation(); // Logout via Mobile SDK await logoutEmployeeAgent(); // Reset SDK state await AgentforceService.resetSettings(); } ``` ### Session Persistence The Mobile SDK handles session persistence natively. Tokens are stored securely and survive app restarts. The `EmployeeAgentAuthBridge` delegates all storage to the Mobile SDK. ## See Also - [Configure the SDK](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-react-native-integration.md) - [Install the SDK](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-react-native-install.md) - [Troubleshooting](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-react-native-troubleshooting.md) # EmployeeAgentConfiguration `class EmployeeAgentConfiguration` ## Types ### Builder ```kotlin class Builder(user: User, forceConfigEndpoint: String) ``` Constructor for creating EmployeeAgentConfiguration instances. #### Functions ```kotlin fun build(): EmployeeAgentConfiguration ``` Creates an EmployeeAgentConfiguration instance. ### Companion ```kotlin object Companion ``` ## Properties | Property | Type | Description | | --------------------- | -------- | ---------------------------- | | `forceConfigEndpoint` | `String` | Salesforce instance endpoint | | `user` | `User` | User instance | ## Related Documentation - [AgentforceMode](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-mode-android.md) - [AgentforceConfiguration](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-configuration-android.md) # EmployeeAgentConfiguration ## Overview Streamlined configuration for employee agent integrations with automatic defaults. Provides configuration settings specifically for employee agent interactions with simplified setup. ## Declaration ```swift struct EmployeeAgentConfiguration ``` ## Properties | Property | Type | Description | | ---------------------- | ----- | --------------------------------------------------- | | _No public properties_ | _N/A_ | Configuration is set through initializer parameters | ## Methods | Method | Signature | Description | | --------------------------------- | ----------------------------------------------- | ----------------------------------------------------------------- | | `init(user:forceConfigEndpoint:)` | `init(user: User, forceConfigEndpoint: String)` | Creates a new employee agent configuration with user and endpoint | # Error Handling Reference - React Native Reference documentation for error handling in the Agentforce Mobile SDK for React Native. ## Overview Errors are thrown as JavaScript `Error` objects with a `code` property. Catch them in Promise rejections: ```tsx try { await AgentforceService.configure(config); } catch (error) { console.log(error.code); // e.g. 'INVALID_CONFIG' console.log(error.message); // Human-readable description } ``` ## AgentforceModule Error Codes | Code | Source | Description | | ----------------- | ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | | `INVALID_CONFIG` | `configure`, `registerViewProvider` | Missing or invalid configuration fields. Missing `type` field, invalid type value, missing required fields, or empty componentMap. | | `CONFIG_ERROR` | `configure` | Configuration failed at the native SDK level (for example, network error, invalid credentials). | | `NOT_CONFIGURED` | `launchConversation`, `startNewConversation` | `configure()` was not called before attempting to launch. | | `LAUNCH_ERROR` | `launchConversation` (iOS) | Failed to start the conversation session. Often indicates wrong `serviceApiURL` (400) or server error (500). | | `START_NEW_ERROR` | `startNewConversation` (iOS) | Failed to start a new conversation. | | `ERROR` | `launchConversation`, `startNewConversation` (Android) | General Android error (Activity not available, initialization failure). | | `INVALID_CONTEXT` | `setAdditionalContext` | Missing `variables` array or a variable lacks `name`/`type`. | | `NO_CONVERSATION` | `setAdditionalContext` | No active conversation. Must call `launchConversation()` first. | | `CONTEXT_ERROR` | `setAdditionalContext` | The native SDK rejected the context. | | `INVALID_FIELDS` | `registerHiddenPreChatFields` (iOS) | Fields are not a valid string-to-string map. | ## EmployeeAgentAuthBridge Error Codes | Code | Source | Description | | ---------------- | ------------------------------------------- | ----------------------------------------- | | `NO_ACTIVITY` | `login`, `refreshAuthCredentials` (Android) | No current Activity available. | | `NOT_AVAILABLE` | `login`, `refreshAuthCredentials` (Android) | Salesforce SDK not initialized. | | `LOGIN_FAILED` | `login` (Android) | No credentials obtained after login flow. | | `REFRESH_FAILED` | `refreshAuthCredentials` (Android) | No credentials available after refresh. | | `ERROR` | Various (Android) | General error with message. | ## Handling Configuration Errors ```tsx try { await AgentforceService.configure({ type: "service", serviceApiURL: url, organizationId: orgId, esDeveloperName: devName, }); } catch (error) { switch (error.code) { case "INVALID_CONFIG": console.error("Configuration is invalid:", error.message); break; case "CONFIG_ERROR": console.error("SDK configuration failed:", error.message); break; default: console.error("Unknown error:", error); } } ``` ## Handling Launch Errors ```tsx try { await AgentforceService.launchConversation(); } catch (error) { switch (error.code) { case "NOT_CONFIGURED": console.error("Call configure() first"); break; case "LAUNCH_ERROR": // iOS-specific: session start failed console.error("Session failed - check serviceApiURL"); break; case "ERROR": // Android-specific: general error console.error("Launch failed:", error.message); break; default: console.error("Unknown error:", error); } } ``` ## Handling Context Errors ```tsx try { await AgentforceService.setAdditionalContext({ variables: [{ name: "userId", type: "Text", value: "123" }], }); } catch (error) { switch (error.code) { case "INVALID_CONTEXT": console.error("Context format is invalid"); break; case "NO_CONVERSATION": console.error("Launch conversation first"); break; case "CONTEXT_ERROR": console.error("SDK rejected the context"); break; } } ``` ## Context Variable Validation The bridge performs client-side validation before sending to native: 1. The `context` object must have a `variables` array. 2. Each variable must have a non-empty `name` (string) and `type` (string). 3. The `type` must be one of: `Text`, `Number`, `Boolean`, `Date`, `DateTime`, `Json`, `List`, `Money`, `Object`, `Ref`, `Variable`. If validation fails, a synchronous `Error` is thrown before the native call. ## Platform Error Differences | Method | iOS Error Code | Android Error Code | | ------------------------------ | ----------------- | ------------------ | | `launchConversation` failure | `LAUNCH_ERROR` | `ERROR` | | `startNewConversation` failure | `START_NEW_ERROR` | `ERROR` | | Invalid hidden prechat fields | `INVALID_FIELDS` | (not validated) | ## See Also - [Troubleshooting Guide](/docs/ai/agentforce-mobile-sdk/guide/react-native/agentforce-mobile-sdk-react-native-troubleshooting) - [Configuration Reference](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/configuration-overview-react-native.md) # EscalationAction ## Overview Actions that can be performed on escalation status. An enumeration that defines the available actions for handling escalation scenarios in conversations. ## Declaration ```swift enum EscalationAction ``` ## Properties | Property | Type | Description | | --------------- | ----- | ---------------------------------------------- | | _No properties_ | _N/A_ | Enumeration cases define the available actions | ## Methods | Method | Signature | Description | | -------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | _Enumeration Cases_ | `case cancel` | Cancel the escalation action | | _Enumeration Cases_ | `case refresh` | Refresh the escalation status | | _Inherited from Equatable_ | _Equality operators_ | Inherits equality comparison methods. See [Equatable (_Apple Developer_)](https://developer.apple.com/documentation/Swift/Equatable) | # EscalationStatusView ## Overview A SwiftUI view for displaying escalation status and queue information. Provides visual feedback about the current state of human agent escalation, including queue position, wait times, and agent assignment status. ## Declaration ```swift @MainActor struct EscalationStatusView ``` ## Properties | Property | Type | Description | | -------- | ----------- | ------------------------------------------- | | `body` | `some View` | The main view content (inherited from View) | ## Methods | Method | Signature | Description | | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | `init(escalation:showQueueDetails:isCompact:onAction:)` | `init(escalation: EscalationStatusMessage, showQueueDetails: Bool = true, isCompact: Bool = false, onAction: ((EscalationAction) -> Void)? = nil)` | Creates an escalation status view with the specified configuration | | _Inherited from View_ | _All View protocol methods_ | Inherits all standard SwiftUI View methods and modifiers. See [View (_Apple Developer_)](https://developer.apple.com/documentation/swiftui/view) | ## Usage Examples ### Basic Escalation Status ```swift EscalationStatusView( escalation: escalationMessage, showQueueDetails: true ) ``` ### Compact Status Indicator ```swift EscalationStatusView( escalation: escalationMessage, showQueueDetails: false, isCompact: true ) ``` # Example - Configure String Replacement for Agent Username This example shows you one way to use [string replacement](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_ws_string_replace.htm) to update the agent's username during deployment. This method works with committed and uncommitted agents. In this example, we: - Specify the string to replace as `digitalagent.00dob000002dgxhf324f6b53d31@salesforce.com`. - Specify that the environment variable `TARGET_AGENT_USER` will hold the new username. - Pass the new username on the command line, rather than setting the environment variable. ### Step 1 - Find Your Source Org's Username In the source org, find the username for the agent's default user. The username is defined in an agent's `.agent` file, in the `default_agent_user` property. For example: ```bash default_agent_user: "digitalagent.00dob000002dgxhf324f6b53d31@salesforce.com" ``` ### Step 2 - Update Your sfdx-project.json File In your Salesforce DX project's `sfdx-project.json` file, configure your `replacements` property. Be sure to replace all instances of the agent username. In this example, we specify replacement in all metadata (`*-meta.xml`) and agent script (`*.agent`) files. We use the environment variable `TARGET_AGENT_USER` for string substitution. (Your project's needs might be different). ```bash { "packageDirectories": [ { "path": "force-app", "default": true } ], "name": "test_metadata_string", "namespace": "", "sfdcLoginUrl": "https://login.salesforce.com", "sourceApiVersion": "66.0", "replacements": [ { "glob": "force-app/main/default/bots/**/*-meta.xml", "stringToReplace": "digitalagent.00dob000002dgxhf324f6b53d31@salesforce.com", "replaceWithEnv": "TARGET_AGENT_USER" }, { "glob": "force-app/main/default/aiAuthoringBundles/**/*.agent", "stringToReplace": "digitalagent.00dob000002dgxhf324f6b53d31@salesforce.com", "replaceWithEnv": "TARGET_AGENT_USER" } ] } ``` ### Step 3 - Specify Source Username During Deployment When [executing the deployment](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-deploy-metadata.md##step-7-deploy-agent-metadata-to-a-new-org), assign the target org's agent username to the TARGET_AGENT_USER environment variable. ```bash TARGET_AGENT_USER="digitalagent.00dob000002dgw5b9802e014bf4@salesforce.com" sf project deploy start --source-dir force-app --target-org my-target ``` # Example: Customizing User Interface Using Custom Lightning Types with Top-Level Collection Renderer Override This example explains how to override the default user interface to create a customized appearance of responses on the custom agent’s action output with custom Lightning types. In this example, you specify a renderer collection override for the custom Lighting type that you created. ## Before You Begin Download these sample data files. - [apexClass.zip](https://resources.docs.salesforce.com/rel1/doc/en-us/static/misc/apexClassesExample.zip) - [hotelLWCandCLT.zip](https://resources.docs.salesforce.com/rel1/doc/en-us/static/misc/hotelLWCAndCLT4.zip) ## Example Apex Class for Retrieving Hotel Information Use these Apex classes together to create a custom agent action that finds available hotels. The main `HotelReservation` class contains the invocable method, and the other classes define the complex data structures for the request and response. When you create your custom agent action, select the method **Find hotels**. **HotelReservation Class** This class is the main class that contains the logic for the `find hotels` agent action. ```apex @JsonAccess(serializable='always' deserializable='always') global class HotelReservation { @InvocableMethod(label='Find hotels ' description='Find Available Hotels') global static List findHotels(List req) { // For example, we hardcode the data and don’t focus on how we retrieve it. // However, consider that we receive available hotel data from a service // and then iterate through the data to generate the final response. List hotelResponseList = new List(); Room r1 = new Room('DELUX', 2, 15.15d, 2000l, false); List rooms = new List(); rooms.add(r1); HotelCategory fourStar = new HotelCategory('four'); Hotel hotel1 = new Hotel('Sahara Hotels', 'Gacchibowli Hyderabad', rooms, fourStar); HotelCategory fiveStar = new HotelCategory('five'); Hotel hotel2 = new Hotel('Taj Vivanta', 'Kokapet', rooms, fiveStar); List hotels = new List(); hotels.add(hotel1); hotels.add(hotel2); HotelResponse hotelresponse = new HotelResponse(hotels); hotelResponseList.add(hotelresponse); return hotelResponseList; } } ``` **HotelResponse Class** This class defines the data structure for the response that returns a list of available hotels. ```apex @JsonAccess(serializable='always' deserializable='always') global class HotelResponse { @InvocableVariable global List hotels; global HotelResponse(List hotels) { this.hotels = hotels; } } ``` **Hotel Class** This class defines the data structure for hotel details. ```apex @JsonAccess(serializable='always' deserializable='always') global class Hotel { @InvocableVariable global String name; @InvocableVariable global String address; @InvocableVariable global List rooms; @InvocableVariable global HotelCategory hotelCategory; global Hotel(String name, String address, List rooms, HotelCategory hotelCategory) { this.name = name; this.address = address; this.rooms = rooms; this.hotelCategory = hotelCategory; } } ``` **Room Class** This class defines the data structure for rooms within a hotel. ```apex @JsonAccess(serializable='always' deserializable='always') global class Room { @InvocableVariable global String type; @InvocableVariable global Integer available; @InvocableVariable global Double discountPercentage; @InvocableVariable global Long price; @InvocableVariable global Boolean petAllowed; global Room(String type, Integer available, Double discountPercentage, Long price, Boolean petAllowed) { this.type = type; this.available = available; this.discountPercentage = discountPercentage; this.price = price; this.petAllowed = petAllowed; } } ``` **HotelCategory Class** This class defines the data structure for a hotel’s star rating. ```apex @JsonAccess(serializable='always' deserializable='always') global class HotelCategory { @InvocableVariable global String star; global HotelCategory(String star) { this.star = star; } } ``` **HotelRequest Class** This class defines the data structure for the agent action’s input criteria. ```apex @JsonAccess(serializable='always' deserializable='always') global class HotelRequest { @InvocableVariable global String city; @InvocableVariable global Date checkInDate; @InvocableVariable global Date checkOutDate; } ``` The Apex class `Hotel Reservation` accepts the hotel search criteria, including the check in date, check out date, and city, and then returns a list of available hotels. **note:** For this example, hotel availability data is already included in the `Hotel Reservation` Apex class. However, in a real-time scenario, hotel information is fetched from an external service, and the Apex class processes that data to generate the final response. ## Set Up the Agent and Action in Agentforce Builder Before you can add custom Lightning types to agent actions, create the agent and configure it to use your Apex class. 1. From the **Agentforce Studio** app, create a new Agentforce Employee Agent or Agentforce Service Agent and name it (for example, `Hotel Search Agent`). 2. Open your agent, create a new subagent named `Hotel Search`, and open it to add actions. 3. Add a new action named `Find hotels` to your subagent, set the `Reference Action Type` to **Apex**, and select the **Find hotels** method from the `HotelReservation` class you deployed earlier. 4. Switch to Script mode and add `is_user_input: True` to each input that the agent collects from the user. 5. In the Hotel Search subagent, add instructions that tell the agent when to use the action and what data to collect. For example: "When a customer asks about hotel availability or wants to search for hotels, use the {!@actions.Find_hotels} action. Collect the checkin date, checkout date, and city from the customer before running the action." This code shows the `Hotel_Search` subagent and `Find_hotels` action that the preceding steps create. To create the same configuration directly, add this code to the agent script. ```agentscript subagent Hotel_Search: label: "Hotel Search" description: | Search hotels reasoning: instructions: -> | When a customer asks about hotel availability or wants to search for hotels, use the {!@actions.Find_hotels} action. Collect the checkin date, checkout date, and city from the customer before running the action. actions: Find_hotels: @actions.Find_hotels with checkInDate = ... with checkOutDate = ... with city = ... actions: Find_hotels: label: "Find hotels" description: "find available hotels" target: "apex://HotelReservation" inputs: checkInDate: object label: "checkInDate" is_required: True is_user_input: True complex_data_type_name: "lightning__dateType" description: "checkin date" checkOutDate: object label: "checkOutDate" is_required: True is_user_input: True complex_data_type_name: "lightning__dateType" description: "checkout date" city: string label: "city" is_required: True is_user_input: True description: "city" outputs: hotels: list[object] label: "hotels" complex_data_type_name: "@apexClassType/c__Hotel" is_displayable: True filter_from_agent: False description: "result" ``` When you add the code directly to the agent script, also add this transition to the Agent Router’s `actions` section to route hotel-search requests to the `Hotel Search` subagent. ```agentscript go_to_Hotel_Search: @utils.transition to @subagent.Hotel_Search ``` This image shows the transition in the Agent Router’s actions section. ![Agent Router in Script mode with the go_to_Hotel_Search transition in its actions section.](https://developer.salesforce.com/media/lightning-types-images/hotel-agent.png '{"class": "image-framed"}') **note:** Agent Script identifiers are case-sensitive. The `@subagent.Hotel_Search` reference must match the identifier in the subagent `Hotel_Search` declaration. **See Also** - [Create an Agent](https://help.salesforce.com/s/articleView?id=ai.agent_setup_create.htm&type=5) - [Create a Custom Subagent](https://help.salesforce.com/s/articleView?id=ai.agent_topics_add_custom.htm&type=5) - [Create a Custom Action](https://help.salesforce.com/s/articleView?id=ai.agent_actions_custom.htm&type=5) - [Add an Action to a Subagent from the Asset Library](https://help.salesforce.com/s/articleView?id=ai.agent_actions_add_asset_library.htm&type=5) - [How Subagent Instructions are Resolved to Build a Prompt](https://help.salesforce.com/s/articleView?id=ai.agent_topics_instructions_resolve.htm&type=5) ## Actions Inputs and Outputs Inputs and outputs for the agent action are defined by using standard Lightning types. Input: - `checkInDate`, `checkOutDate`, and `city` use standard Lightning types such as lightning\_\_dateType and lightning\_\_textType. Output: - The output `hotels` for the agent action is a list type. Here’s an image that shows the custom agent action created. ![Input and output settings for a 'Find hotels' agent action. Inputs: checkInDate, checkOutDate, City. Output: hotels.](https://developer.salesforce.com/media/lightning-types-images/hotel-update.png '{"class": "image-framed"}') The available flight information is retrieved by using `@apexClassType/c__Hotel` in the agent action output, where: - `apexClassType` is the bundle name. - `Hotel` is the Apex class. When you execute this agent action, it prompts you to provide input and then generates the output. ## Agent Action Execution Input The agent’s action UI collects these details to find available hotels. - Check in date - Check out date - City Here’s the image that shows how the custom agent action input appears in an agent conversation. ![Agent action input collects hotel details: checkInDate, checkOutDate, and city.](https://developer.salesforce.com/media/lightning-types-images/Example-Execution-Hotel-Input.png '{"class": "image-md image-framed"}') ## Agent Action Execution Output The agent’s action UI returns the available hotel details. Here’s the image that shows how the custom agent action’s output appears in an agent conversation. ![Agent's response to a hotel details request. The response lacks labels and is presented in a format that is hard to understand.](https://developer.salesforce.com/media/lightning-types-images/Example-Execution-Hotel-Output.png '{"class": "image-md image-framed"}') ## Result Data The agent displays the hotel data in the response. Here’s the sample code that shows the available hotel data. ```json { "hotels": [ { "rooms": [ { "type": "DELUX", "price": 2000, "petAllowed": false, "discountPercentage": 15.15, "available": 2 } ], "name": "Sahara Hotels", "hotelCategory": { "star": "four" }, "address": "Gacchibowli Hyderabad" }, { "rooms": [ { "type": "DELUX", "price": 2000, "petAllowed": false, "discountPercentage": 15.15, "available": 2 } ], "name": "Taj Vivanta", "hotelCategory": { "star": "five" }, "address": "Kokapet" } ] } ``` ## Customize UI for Output Create a custom Lightning type named `hotelResponse` to enhance the visibility of the information in the output UI. ### Override Default UI for Output With Custom Lightning Types Override the agent’s action UI for output to enhance the user experience by using Custom Lightning Types (CLTs). With CLTs, you can add your own Lightning Web Components (LWC) to present data for lists in a more structured and intuitive format. Configure the `renderer.json` file to override the default UI of a custom Lightning type in the agent action. Here’s an example showing a lightningTypes folder for a custom Lightning type named `hotelResponse`. ``` +--lightningTypes +--hotelResponse +--schema.json +--lightningDesktopGenAi +--renderer.json ``` **note:** This example uses `lightningDesktopGenAi` to configure the custom Lightning type. To configure the type for the `enhancedWebChat` channel, create the `renderer.json` file in the corresponding channel folder. This image shows an example of the `hotelResponse` folder structure. ![The hotelResponse folder contains schema.json and the enhancedWebChat and lightningDesktopGenAi folders. Each channel folder contains a renderer.json file.](https://developer.salesforce.com/media/lightning-types-images/output-folder-hotel.png '{"class": "image-md image-framed"}') The custom Lightning type `hotelResponse` includes a `schema.json` file and a `renderer.json` file. The `renderer.json` file controls how the data is displayed to the user in the agent action output. This sample code shows the contents of the `schema.json file`. ```json { "title": "Hotel Reservation", "description": "Hotel Reservation", "lightning:type": "@apexClassType/c__Hotel" } ``` This sample code shows the contents of the `renderer.json` file. ```json { "collection": { "renderer": { "componentOverrides": { "$": { "definition": "c/hotelDetails" } } } } } ``` ### Build Output Components with Lightning Web Components This section explains how the components are created and deployed for agent action output. This image shows the Lightning Web Component (LWC) folder structure. ![The lwc folder contains a folder named hotelDetails, which is the LWC component. The hotelDetails folder includes CSS, HTML, JS, and metadata files.](https://developer.salesforce.com/media/lightning-types-images/Example2-Output-LWC.png '{"class": "image-md image-framed"}') The LWC component includes HTML markup designed to accept output for `@apexClassType/c__Hotel`. This HTML markup ensures that the data is displayed in an intuitive and customized format. This sample code shows the contents of the `hotelDetails.js-meta.xml` file. ```xml 64.0 true HotelDetails lightning__AgentforceOutput ``` **note:** When you create an LWC component to override the UI for action input, use `lightning__AgentforceInput` as the target. For output, use `lightning__AgentforceOutput`. For information about LWC target types, see [`lightning__AgentforceInput` Target](https://developer.salesforce.com/docs/platform/lwc/guide/targets-lightning-agentforce-input.html) and [`lightning__AgentforceOutput` Target](https://developer.salesforce.com/docs/platform/lwc/guide/targets-lightning-agentforce-output.html). This sample code shows the contents of the `hotelDetails.html` file. ```html ``` This sample code shows the contents of the `hotelDetails.js` file. ```js import { LightningElement, api } from "lwc"; export default class HotelDetails extends LightningElement { @api value; } ``` **See Also** - _Lightning Web Components Developer Guide_: [Get Started with Lightning Web Components](https://developer.salesforce.com/docs/platform/lwc/guide) ### Configure Custom Lightning Type for Output in Agent Script After you create a custom Lightning type and Lightning Web Component, configure the agent action to use them. 1. In **Agentforce Builder**, open your agent. 2. In the **Explorer** panel, go to your subagent and select the **Find hotels** action. 3. Switch to **Script** mode using the toggle at the top of the canvas. 4. Locate the `filters` output parameter in the action configuration 5. Replace the existing value of the `complex_data_type_name` property ‌with `c__hotelResponse`. Custom Lightning types use the `c__` namespace prefix. 6. Click **Save**. **note:** The script will fail validation if you specify a non-existent custom Lightning type name. Here's an image that shows the custom Lightning type configured in Script mode: ![The agent action outputs parameter with 'c__hotelResponse' selected in the `complex_data_type_name` property.](https://developer.salesforce.com/media/lightning-types-images/hotel-output.png '{"class": "image-md image-framed"}') **See Also** - [Agent Script Reference: Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-actions.html#outputs) ## Test, Commit, and Activate Your Agent After you configure the custom Lightning types for output in the agent script, preview the conversation to verify the user experience. Once you're satisfied with the customized UIs, commit and activate your agent to make it available to users. 1. In **Agentforce Builder**, click the **Preview** tab. 2. Enter a test utterance, such as "Find hotels." 3. When the agent prompts for details, enter the input and review the agent's final response to verify that the hotel data renders using your custom `hotelResponse` LWC cards. This image shows how the custom agent action’s output appears in an agent conversation. ![Agent's response to a hotel details request. The response includes clear labels and is presented in a format that is easy to understand.](https://developer.salesforce.com/media/lightning-types-images/example2-output.png '{"class": "image-sm image-framed"}') 4. At the top of the canvas, click **Commit Version** and then click **Commit** to confirm. **note:** To make further changes after this point, you must create a new draft from the committed version. 5. With the committed version selected, click **Activate** and confirm the activation to make the agent available to users. The currently active version (if any) is automatically deactivated. **See Also** - [Explore Agentforce Builder](https://help.salesforce.com/s/articleView?id=ai.agent_builder_tour.htm&type=5) - [Commit an Agent Version](https://help.salesforce.com/s/articleView?id=ai.agent_versions_commit.htm&type=5) - [Activate or Deactivate Your Agent](https://help.salesforce.com/s/articleView?id=ai.copilot_setup_activate_deactivate.htm&type=5) # Example: Customizing User Interface Using Custom Lightning Types with Top-Level Editor and Top-Level Renderer Overrides This example explains how to override the default user interface to create a customized appearance of responses on the custom agent’s action input and output with custom Lightning types. In this example, you specify an editor override and a renderer override for the custom Lightning type that you created. ## Before You Begin Download these sample data files. - [apexClass.zip](https://resources.docs.salesforce.com/rel1/doc/en-us/static/misc/apexClassExample.zip) - [flightResponseCLTandLWC.zip](https://resources.docs.salesforce.com/rel1/doc/en-us/static/misc/flightResponseCLTAndLWC4.zip) - [flightFiltersCLTandLWC.zip](https://resources.docs.salesforce.com/rel1/doc/en-us/static/misc/flightFilterCLTAndLWCExample.zip) ## Example Apex Class for Retrieving Flight Information Use these Apex classes together to create a custom agent action that finds flights. The main `FlightAgent` class contains the invocable method, and the other classes define the complex data structures for the request and response. When you create your custom agent action, select the method **Find Flights**. **FlightAgent Class** This class is the main class that contains the logic for the `Find Flights` agent action. It also defines the `FlightRequest` and `FlightResponse` inner classes to handle the action's input and output. ```apex global class FlightAgent { @InvocableMethod(label='Find Flights' description='Finds available flights') global static List findFlights(List req) { List flightResponses = new List(); // For example, we hardcode the data and don’t focus on how we retrieve it. // However, consider that we receive available flight data from a service // and then iterate through the data to generate the final response. List flights = new List(); Flight f1 = new Flight('IX 2814', 1, false, 1000l, 20.20d, 70); Flight f2 = new Flight('6E 488', 2, false, 2000l, 15.15d, 120); Flight f3 = new Flight('6E 523', 1, false, 3000l, 13.14d, 75); Flight f4 = new Flight('6E 6166', 2, false, 4000l, 14.14d, 130); flights.add(f1); flights.add(f2); flights.add(f3); flights.add(f4); AvailableFlight availableFlights = new AvailableFlight(); availableFlights.flights = flights; FlightResponse fr = new FlightResponse(); fr.aFlight = availableFlights; flightResponses.add(fr); return flightResponses; } @JsonAccess(serializable='always' deserializable='always') global class FlightRequest { @InvocableVariable global String originCity; @InvocableVariable global String destinationCity; @InvocableVariable global Date dateOfTravel; @InvocableVariable global FlightRequestFilter filters; } @JsonAccess(serializable='always' deserializable='always') global class FlightResponse { @InvocableVariable global AvailableFlight aFlight; } } ``` **AvailableFlight Class** This class defines a list that holds multiple Flight objects. ```apex @JsonAccess(serializable='always' deserializable='always') global class AvailableFlight { @AuraEnabled global List flights; } ``` **Flight Class** This class defines the data structure for flight details. ```apex @JsonAccess(serializable='always' deserializable='always') global class Flight { @AuraEnabled global String flightId; @AuraEnabled global Integer numLayovers; @AuraEnabled global Boolean isPetAllowed; @AuraEnabled global Long price; @AuraEnabled global Double discountPercentage; @AuraEnabled global Integer durationInMin; global Flight(String flightId, Integer numLayovers, Boolean isPetAllowed, Long price, Double discountPercentage, Integer durationInMin) { this.flightId = flightId; this.numLayovers = numLayovers; this.isPetAllowed = isPetAllowed; this.price = price; this.discountPercentage = discountPercentage; this.durationInMin = durationInMin; } } ``` **FlightRequestFilter** This class defines the data structure for the optional filters a user can apply when searching for flights. ```apex @JsonAccess(serializable='always' deserializable='always') global class FlightRequestFilter { @AuraEnabled global Long price; @AuraEnabled global Double discountPercentage; } ``` The Apex class `FlightAgent` accepts the flight search criteria, including the origin city, destination city, and date of travel, and then returns a list of available flights. **note:** For this example, flight availability data is already included in the `FlightAgent` Apex class. However, in a real-time scenario, flight information is fetched from an external service, and the Apex class processes that data to generate the final response. ## Set Up the Agent and Action in Agentforce Builder Before you can add custom Lightning types to agent actions, create the agent and configure it to use your Apex class. 1. From the **Agentforce Studio** app, create a new Agentforce Employee Agent or Agentforce Service Agent and name it (for example, `Flight Search Agent`). 2. Open your agent, create a new subagent named `Flight Search`, and open it to add actions. 3. Add a new action named `Find Flights` to your subagent, set the `Reference Action Type` to **Apex**, and select the **Find Flights** method from the `FlightAgent` class you deployed earlier. 4. Switch to Script mode and add `is_user_input: True` to each input that the agent collects from the user. 5. In the Flight Search subagent, add instructions that tell the agent when to use the action and what data to collect. For example: "When a customer asks about flight availability or wants to search for flights, use the {!@actions.Find_Flights} action. Collect the origin city, destination city, and date of travel from the customer before running the action." This code shows the `Flight_Search` subagent and `Find_Flights` action that the preceding steps create. To create the same configuration directly, add this code to the agent script. ```agentscript subagent Flight_Search: label: "Flight Search" description: | Search flights reasoning: instructions: -> | When a customer asks about flight availability or wants to search for flights, use the {!@actions.Find_Flights} action. Collect the origin city, destination city, and date of travel from the customer before running the action. actions: Find_Flights: @actions.Find_Flights with dateOfTravel = ... with destinationCity = ... with filters = ... with originCity = ... actions: Find_Flights: label: "Find Flights" description: "find available flights" target: "apex://FlightAgent" inputs: dateOfTravel: object label: "dateOfTravel" is_required: True is_user_input: True complex_data_type_name: "lightning__dateType" description: "date info" destinationCity: string label: "destinationCity" is_required: True is_user_input: True description: "city info" filters: object label: "filters" is_required: True is_user_input: True complex_data_type_name: "@apexClassType/c__FlightRequestFilter" description: "filters" originCity: string label: "originCity" is_required: True is_user_input: True description: "city" outputs: aFlight: object label: "aFlight" complex_data_type_name: "@apexClassType/c__AvailableFlight" is_displayable: True filter_from_agent: False description: "result" ``` When you add the code directly to the agent script, also add this transition to the Agent Router’s `actions` section to route flight-search requests to the `Flight Search` subagent. ```agentscript go_to_Flight_Search: @utils.transition to @subagent.Flight_Search ``` This image shows the transition in the Agent Router’s actions section. ![Agent Router in Script mode with the go_to_Flight_Search transition in its actions section.](https://developer.salesforce.com/media/lightning-types-images/flight-agent.png '{"class": "image-framed"}') **note:** Agent Script identifiers are case-sensitive. The `@subagent.Flight_Search` reference must match the identifier in the subagent `Flight_Search` declaration. **See Also** - [Create an Agent](https://help.salesforce.com/s/articleView?id=ai.agent_setup_create.htm&type=5) - [Create a Custom Subagent](https://help.salesforce.com/s/articleView?id=ai.agent_topics_add_custom.htm&type=5) - [Create a Custom Action](https://help.salesforce.com/s/articleView?id=ai.agent_actions_custom.htm&type=5) - [Add an Action to a Subagent from the Asset Library](https://help.salesforce.com/s/articleView?id=ai.agent_actions_add_asset_library.htm&type=5) - [How Subagent Instructions are Resolved to Build a Prompt](https://help.salesforce.com/s/articleView?id=ai.agent_topics_instructions_resolve.htm&type=5) ## Action Inputs and Outputs Inputs and outputs for the agent action are defined by using standard Lightning types and Apex classes. Input: - `dateOfTravel`, `destinationCity`, and `originCity` use standard Lightning types such as lightning\_\_dateType and lightning\_\_textType. - The `filters` input is a complex type that references an Apex class. Output: - The output `aFlight` for the agent action is a complex type that references an Apex class. Here’s an image that shows the custom agent action created. ![Input and output settings for a 'Find Flights' agent action. Inputs: dateOfTravel, destinationCity, filters, originCity. Output: aFlight.](https://developer.salesforce.com/media/lightning-types-images/flight-update.png '{"class": "image-framed"}') The available flight information is retrieved by using `@apexClassType/c__AvailableFlight` in the agent action output, where: - `apexClassType` is the bundle name. - `AvailableFlight` is the Apex class. When you execute this agent action, it prompts you to provide input and then generates the output. ## Agent Action Execution Input The agent’s action UI collects these details to find available flights. - Origin city - Destination city - Date of travel Here’s the image that shows how the custom agent action input appears in an agent conversation. ![Agent's response to collect flight details. The response lacks filter details for price and discount percentage, making it difficult to filter flight data.](https://developer.salesforce.com/media/lightning-types-images/Example1-Input-Action.png '{"class": "image-md image-framed"}') ## Agent Action Execution Output The agent’s action UI returns the available flight details. Here’s the image that shows how the custom agent action’s output appears in an agent conversation. ![Agent's response to a flight details request. The response lacks labels and is presented in a format that is hard to understand.](https://developer.salesforce.com/media/lightning-types-images/Example-Execution-Output.png '{"class": "image-md image-framed"}') ## Result Data The agent displays the flight data in the response. Here’s the sample code that shows the available flight data. ```json { "aFlight": { "flights": [ { "price": 1000, "numLayovers": 1, "isPetAllowed": false, "flightId": "IX 2814", "durationInMin": 70, "discountPercentage": 20.2, "departureTime": "08:30" }, { "price": 2000, "numLayovers": 2, "isPetAllowed": true, "flightId": "6E 488", "durationInMin": 120, "discountPercentage": 15.15, "departureTime": "09.00" } ] } } ``` ## Customize UI for Output Create a custom Lightning type named `flightResponse` to enhance the visibility of the information in the output UI. ### Override Default UI for Output With Custom Lightning Types Override the agent’s action UI for output to enhance the user experience by using Custom Lightning Types (CLTs). With CLTs, you can add your own Lightning Web Components (LWC) to present data in a more structured and intuitive format. Configure the `renderer.json` file to override the default UI of a custom Lightning type in the agent action. Here’s an example showing a lightningTypes folder for a custom Lightning type named `flightResponse`. ``` +--lightningTypes +--flightResponse +--schema.json +--lightningDesktopGenAi +--renderer.json ``` **note:** This example uses `lightningDesktopGenAi` to configure the custom Lightning type. To configure the type for the `enhancedWebChat` channel, create the `renderer.json` file in the corresponding channel folder. This image shows an example of the `flightResponse` folder structure. ![The flightResponse folder contains schema.json and the enhancedWebChat and lightningDesktopGenAi folders. Each channel folder contains a renderer.json file.](https://developer.salesforce.com/media/lightning-types-images/output-folder.png '{"class": "image-md image-framed"}') The custom Lightning type `flightResponse` includes a `schema.json` file and a `renderer.json` file. The `renderer.json` file controls how the data is displayed to the user in the agent action output. This sample code shows the contents of the `schema.json` file. ```json { "title": "My Flight Response", "description": "My Flight Response", "lightning:type": "@apexClassType/c__AvailableFlight" } ``` This sample code shows the contents of the `renderer.json` file. ```json { "renderer": { "componentOverrides": { "$": { "definition": "c/flightDetails" } } } } ``` **See Also** - _Metadata API Developer Guide_: [LightningTypeBundle](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_lightningtypebundle.htm) ### Build Output Components with Lightning Web Components This section explains how the components are created and deployed for agent action output. This image shows the Lightning Web Component (LWC) folder structure. ![The lwc folder contains a folder named flightDetails, which is the LWC component. The flightDetails folder includes CSS, HTML, JS, and metadata files.](https://developer.salesforce.com/media/lightning-types-images/Example1-Output-LWC.png '{"class": "image-md image-framed"}') The LWC component includes HTML markup designed to represent the data that the agent returns for `@apexClassType/c__AvailableFlight`. This HTML markup ensures that the data is displayed in an intuitive and customized format. This sample code shows the contents of the `flightDetails.js-meta.xml` file. ```xml 64.0 true Flight LWC lightning__AgentforceOutput ``` **note:** When you create an LWC component to override the UI for action input, use `lightning__AgentforceInput` as the target. For output, use `lightning__AgentforceOutput`. For information about LWC target types, see [`lightning__AgentforceInput` Target](https://developer.salesforce.com/docs/platform/lwc/guide/targets-lightning-agentforce-input.html) and [`lightning__AgentforceOutput`Target](https://developer.salesforce.com/docs/platform/lwc/guide/targets-lightning-agentforce-output.html). This sample code shows the contents of the `flightDetails.html` file. ```html ``` This sample code shows the contents of the `flightDetails.js` file. ```javascript import { LightningElement, api } from "lwc"; export default class FlightDetails extends LightningElement { @api value; flightData = []; // Method to convert duration from minutes to hours and minutes formattedDuration(durationInMin) { if (durationInMin) { const hours = Math.floor(durationInMin / 60); // Get whole hours const minutes = durationInMin % 60; // Get remaining minutes return `${hours} hr ${minutes} min`; } return; } // Method to calculate arrival time based on departure time and duration arrivalTime(durationInMin) { const hours = 7, minutes = 0; const departureDate = new Date(2025, 0, 1, hours, minutes); // Sample date for calculation const arrivalDate = new Date(departureDate.getTime() + durationInMin * 60000); // Add duration to departure time const arrivalHours = String(arrivalDate.getHours()).padStart(2, "0"); const arrivalMinutes = String(arrivalDate.getMinutes()).padStart(2, "0"); return `${arrivalHours}:${arrivalMinutes}`; } connectedCallback() { const flights = this.value?.flights || []; this.flightData = flights.map((flight) => ({ ...flight, petAllowedStatus: flight.isPetAllowed ? "Yes" : "No", durationInHr: this.formattedDuration(flight.durationInMin), departureTime: "07:00", arrivalInHr: this.arrivalTime(flight.durationInMin), })); } } ``` **See Also** - _Lightning Web Components Developer Guide_: [Get Started with Lightning Web Components](https://developer.salesforce.com/docs/platform/lwc/guide) ### Configure Custom Lightning Type for Output in Agent Script After you create a custom Lightning type and Lightning Web Component, configure the agent action to use them. 1. In **Agentforce Builder**, open your agent. 2. In the **Explorer** panel, go to your subagent and select the **Find Flights** action. 3. Switch to **Script** mode using the toggle at the top of the canvas. 4. Locate the `aFlight` output parameter in the action configuration 5. Replace the existing value of the `complex_data_type_name` property ‌with `c__flightResponse`. Custom Lightning types use the `c__` namespace prefix. 6. Click **Save**. **note:** The script will fail validation if you specify a non-existent custom Lightning type name. Here's an image that shows the custom Lightning type configured in Script mode: ![The agent action outputs parameter with 'c__flightResponse' selected in the `complex_data_type_name` property.](https://developer.salesforce.com/media/lightning-types-images/flight-output.png '{"class": "image-md image-framed"}') **See Also** - [Agent Script Reference: Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-actions.html#outputs) ## Customize UI for Input Create a custom Lightning type named `flightFilter` to show filters in the input UI that suits your business needs. ### Override Default UI for Input with Custom Lightning Types Override the agent’s action UI for input to enhance the user experience by using Custom Lightning Types (CLTs). With CLTs, you can add your own Lightning Web Components (LWC) to present data in a more structured and intuitive format Configure the `editor.json` file to override the default UI of a custom Lightning type in the agent action. Here’s an example that shows a lightningTypes folder for a custom Lightning type named `flightFilter`. ``` +--lightningTypes +--flightFilter +--schema.json +--lightningDesktopGenAi +--editor.json ``` **note:** This example uses `lightningDesktopGenAi` to configure the custom Lightning type. To configure the type for the `enhancedWebChat` channel, create the `editor.json` file in the corresponding channel folder. This image shows an example of the `flightFilter` folder structure. ![The flightFilter folder contains schema.json and the enhancedWebChat and lightningDesktopGenAi folders. Each channel folder contains an editor.json file.](https://developer.salesforce.com/media/lightning-types-images/input-folder.png '{"class": "image-md image-framed"}') The custom Lightning type `flightFilter` includes a `schema.json` file and an `editor.json` file. The `editor.json` file controls how the data is displayed to the user in the agent action input. This sample code shows the contents of the `schema.json` file. ```json { "title": "Flight Filter", "description": "Flight Filter", "lightning:type": "@apexClassType/c__FlightRequestFilter" } ``` This sample code shows the contents of the `editor.json` file. ```json { "editor": { "componentOverrides": { "$": { "definition": "c/flightRequestFilter" } } } } ``` **See Also** - _Metadata API Developer Guide_: [LightningTypeBundle](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_lightningtypebundle.htm) ### Build Input Components with Lightning Web Components This section explains how the components are created and deployed for agent action input. This image shows the Lightning Web Component (LWC) folder structure. ![The lwc folder contains a folder named flightRequestFilter, which is the LWC component. The flightRequestFilter folder includes CSS, HTML, JS, and metadata files.](https://developer.salesforce.com/media/lightning-types-images/Example1-Input-LWC.png '{"class": "image-md image-framed"}') The LWC component includes HTML markup designed to accept input for `@apexClassType/c__FlightRequestFilter`. This HTML markup ensures that the data is displayed in an intuitive and customized format. This sample code shows the contents of the `flightRequestFilter.js-meta.xml` file. ```xml 64.0 true Flight Filter LWC lightning__AgentforceInput ``` **note:** When you create an LWC component to override the UI for action input, use `lightning__AgentforceInput` as the target. For output, use `lightning__AgentforceOutput`. For information about LWC target types, see [`lightning__AgentforceInput` Target](https://developer.salesforce.com/docs/platform/lwc/guide/targets-lightning-agentforce-input.html) and [`lightning__AgentforceOutput` Target](https://developer.salesforce.com/docs/platform/lwc/guide/targets-lightning-agentforce-output.html). This sample code shows the contents of the `flightRequestFilter.html` file. ```html ``` This sample code shows the contents of the `flightRequestFilter.js` file. ```javascript import { api, LightningElement } from "lwc"; export default class FlightFilter extends LightningElement { @api get readOnly() { return this._readOnly; } set readOnly(value) { this._readOnly = value; } _readOnly = false; _value; @api get value() { return this._value; } set value(value) { this._value = value; } price; discountPercentage; connectedCallback() { if (this.value) { this.price = this.value?.price || ""; this.discountPercentage = this.value?.discountPercentage || ""; } } handleInputChange(event) { event.stopPropagation(); const { name, value } = event.target; this[name] = value; this.dispatchEvent( new CustomEvent("valuechange", { detail: { value: { price: this.price, discountPercentage: this.discountPercentage, }, }, }), ); } } ``` **note:** You must include the `handleInputChange()` function to capture user input, update the component’s state, and notify the parent component (planner component) by using the valuechange event. The function ensures real-time data binding and prevents unwanted event propagation. **See Also** - _Lightning Web Components Developer Guide_: [Get Started with Lightning Web Components](https://developer.salesforce.com/docs/platform/lwc/guide) ### Configure Custom Lightning Type for Input in Agent Script After you create a custom Lightning type and Lightning Web Component, configure the agent action to use them. 1. In **Agentforce Builder**, open your agent. 2. In the **Explorer** panel, go to your subagent and select the **Find Flights** action. 3. Switch to **Script** mode using the toggle at the top of the canvas. 4. Locate the `filters` input parameter in the action configuration. 5. Replace the existing value of the `complex_data_type_name` property with `c__flightFilter`. Custom Lightning types use the `c__` namespace prefix. 6. Click **Save**. **note:** The script will fail validation if you specify a non-existent custom Lightning type name. Here's an image that shows the custom Lightning type configured in Script mode: ![The agent action inputs parameter with 'c__flightFilter' selected in the `complex_data_type_name` property.](https://developer.salesforce.com/media/lightning-types-images/flight-input.png '{"class": "image-md image-framed"}') **note:** In certain instances the large language model (LLM) requests input as text, so make sure to accurately update the subagent instructions for the correct selection of the Override Input component. For example, when you enter a prompt to find flights, the agent executes the Find Flight action. The Find Flight action executes by taking input through a UI form, and not in the form of Text because it includes a price and discount range. **See Also** - [Agent Script Reference: Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-ref-actions.html#outputs) ## Test, Commit, and Activate Your Agent After you configure the custom Lightning types for both input and output in the agent script, preview the conversation to verify the user experience. Once you're satisfied with the customized UIs, commit and activate your agent to make it available to users. 1. In **Agentforce Builder**, click the **Preview** tab. 2. Enter a test utterance, such as "Find flights." 3. When the agent prompts for filter details, verify that the custom input form displays the price and discount fields exactly as you designed them in `flightFilter`. This image shows how the custom agent action’s input appears in an agent conversation. ![Agent's response to collect flight details. The response includes filter fields for price and discount percentage, making it easy to filter flight data.](https://developer.salesforce.com/media/lightning-types-images/Example1-Input-Final.png '{"class": "image-sm image-framed"}') 4. Submit the form and review the agent's final response to verify that the flight data renders using your custom `flightResponse` LWC cards. This image shows how the custom agent action's output appears in an agent conversation: ![Agent's response to a flight details request. The response includes clear labels and is presented in a format that is easy to understand.](https://developer.salesforce.com/media/lightning-types-images/example1-output.png '{"class": "image-sm image-framed"}') 5. At the top of the canvas, click **Commit Version** and then click **Commit** to confirm. **note:** To make further changes after this point, you must create a new draft from the committed version. 6. With the committed version selected, click **Activate** and confirm the activation to make the agent available to users. The currently active version (if any) is automatically deactivated. **See Also** - [Explore Agentforce Builder](https://help.salesforce.com/s/articleView?id=ai.agent_builder_tour.htm&type=5) - [Commit an Agent Version](https://help.salesforce.com/s/articleView?id=ai.agent_versions_commit.htm&type=5) - [Activate or Deactivate Your Agent](https://help.salesforce.com/s/articleView?id=ai.copilot_setup_activate_deactivate.htm&type=5) # Export Agentforce Session Tracing Data (Beta) Extract a single, unified JSON view of a full agent session trace with the Agentforce Session Trace OTel API. Import the output into your favorite observability tool or OpenTelemetry Protocol (OTLP) collector for further investigation. ## About the Agentforce Session Trace OTel API This REST API extracts unified trace, metric and log data from two sources: - [Agentforce Session Tracing data model](https://help.salesforce.com/s/articleView?id=ai.generative_ai_session_trace_data_model.htm) - [Generative AI Audit & Feedback data model](https://help.salesforce.com/s/articleView?id=ai.generative_ai_feedback_data_model.htm) The JSON output includes every step of an Agentforce agent interaction: turns, messages, LLM calls, actions, metric scores, and feedback. The output format conforms with the [OpenTelemetry (OTLP) specification](https://opentelemetry.io/docs/specs/otlp/), which is an open standard for sharing telemetry data with observability platforms and OTLP collectors. ## Beta Release Limitations and Considerations The beta release of the Agentforce Session Trace OTel API has these limitations and considerations: - Only single-session queries are supported (one session ID per API request). Bulk query support is not yet available. - Salesforce Connect API standard rate limits apply (see [Connect REST API Limits](https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/intro_rate_limits.htm?d=afx)). - The API returns data for sessions that started (StartTimestamp) within the previous 72 hours of the API request. ## Get Started ### Prerequisites - Agentforce must be turned on in your Salesforce org. ### Step 1: Turn On Data Collection 1. From Setup, in the Quick Find box, enter **Einstein Generative AI**, and then select **Einstein Audit, Analytics, and Monitoring Setup**. 2. Turn on any of the following features that aren’t turned on: - Agentforce Session Tracing (see [Set Up Agentforce Session Tracing](https://help.salesforce.com/s/articleView?id=ai.generative_ai_session_trace_setup.htm&type=5)) - Audit and Feedback (see [Set Up Einstein Generative AI Audit and Feedback](https://help.salesforce.com/s/articleView?id=ai.generative_ai_feedback_enable.htm&type=5)) ### Step 2: Authenticate Authenticate using OAuth 2.0 using an [external client app (ECA)](https://help.salesforce.com/s/articleView?id=xcloud.external_client_apps.htm&type=5). Alternatively, you can authenticate using your favorite REST client (using the auth token from the external client app). ### Step 3: Submit a REST API Query Run the Agentforce Session Trace OTel API against the REST endpoint, passing in the session ID for the session you want to retrieve. `GET /services/data/v66.0/einstein/audit/otel/{session-id}` Here’s a high-level view of the response showing the spans hierarchy. ![OTel API Response](https://developer.salesforce.com/media/otel-api/otel-api-response.png '{"class": "image-lg"}') ### Step 4: Export the Output to Your Observability Platform Most modern observability platforms (such as Splunk, Datadog, and New Relic) support OpenTelemetry Protocol (OTLP) ingestion. Because the API already returns OpenTelemetry-formatted data, you can feed it directly into the observability platform or into any [OpenTelemetry Protocol (OTLP) collector](https://opentelemetry.io/docs/collector/). ## Share Telemetry Data Using an OTLP Collector You can use an OTLP collector to poll the Agentforce Session Trace OTel API, transform and enrich the data, and export it to an observability platform. Here is an example config for an OTLP collector. ```yaml # otel-collector-config.yaml receivers: # Custom receiver or use http receiver with poller salesforce_otel: endpoint: https://your-instance.salesforce.com auth: authenticator: oauth2client processors: batch: timeout: 10s attributes: actions: - key: source value: salesforce action: insert exporters: otlp/datadog: endpoint: https://api.datadoghq.com headers: DD-API-KEY: ${DD_API_KEY} service: pipelines: traces: receivers: [salesforce_otel] processors: [batch, attributes] exporters: [otlp/datadog] ``` ## Frequently Asked Questions (Beta) 1. **What does the Agentforce Session Trace OTel API return?** A full session trace in OTel ResourceSpans format. The output includes all turns, messages, LLM calls, action executions, metric scores, and feedback signals. All data is pre-joined. No Data Cloud SQL is required. 2. **Do I need Data Cloud enabled?** Yes, for the Beta release. Agentforce Session Tracing data is stored in Data 360. The API queries the data using Data 360 SQL. The long-term Unified Planner native OTel path is designed to reduce this dependency, but it is not available in this beta release. 3. **Does the API enforce data governance and dataspace access?** Yes. The underlying Data 360 query service enforces dataspace and governance rules based on the user context making the API call. The API uses the user context to query only what is allowed. 4. **Does this API replace the existing STDM DMOs and Agent Analytics?** No. The OTel JSON API is additive. It’s designed for pro-code and API-based use cases like debugging, custom evals, and third-party export. The normalized STDM DMOs remain the foundation for Agentforce Studio analytics and observability 5. **What are the Beta limitations?** - Only single-session queries are supported (one session ID per API request). Bulk query support is not yet available. - Salesforce Connect API standard rate limits apply (see [Connect REST API Limits](https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/intro_rate_limits.htm?d=afx)). 6. **How does authentication work?** OAuth 2.0 using an [external client app (ECA)](https://help.salesforce.com/s/articleView?id=xcloud.external_client_apps.htm&type=5). This is the same mechanism as the Agent Builder API. For Beta, no additional permissions beyond standard Agentforce access are required. 7. **Can I send this data to my other observability platform (such as Datadog, Splunk, or New Relic)?** In the beta release, pull data via the API and pipe it to any OTLP-compatible endpoint. The OTel format means that no transformation is needed. **Example**: Call the API in automated to pull multiple traces one by one. Get me all the sessions that happened in one hour. - Call query service to get a session list. - Use that list to query the API. Native push/connector support is planned. 8. **Which OpenTelemetry Specification is used for this API?** This trace uses [OTLP (OpenTelemetry Protocol) v1.0](https://opentelemetry.io/docs/specs/otlp/). # File Library Example In this example, we create a library, add a file, index the file, and poll until the library is ready for use. To complete this example, you must first get an access token and set up shell variables, as described in [Get Started with ADL API](https://developer.salesforce.com/docs/ai/agentforce/guide/adl-get-started.md). ## Step 1: Create a File Library This step creates a new file (SFDRIVE) library and returns a presigned upload URL. ```shell RESPONSE_ADL=$(curl -s -X POST "$ORG_URL/services/data/v66.0/einstein/data-libraries" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "masterLabel": "'"${ADL_Name}"'", "developerName": "'"${ADL_DevName}"'", "groundingSource": { "sourceType": "SFDRIVE" } }') echo "$RESPONSE_ADL" | jq '.' LIBRARY_ID=$(echo "$RESPONSE_ADL" | jq -r '.libraryId') echo "LIBRARY_ID: $LIBRARY_ID" ``` The curl command calls the `einstein/data-libraries` resource. For more information, see [ADL Resource Reference](https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/connect_resources_adl.htm) in the Connect REST API Developer Guide. **Expected Response:** JSON with `libraryId` and `groundingSource` fields. ## Step 2: Wait for Upload Readiness The library needs to provision Data 360 resources before files can be uploaded. This command polls for up to two minutes. If the resources aren't ready after two minutes, you can run the script block again. ```shell echo "Checking upload readiness..." READINESS=$(curl -s --max-time 130 \ "$ORG_URL/services/data/v66.0/einstein/data-libraries/$LIBRARY_ID/upload-readiness?waitMaxTime=120000" \ -H "Authorization: Bearer $ACCESS_TOKEN") echo "$READINESS" | jq '.' ``` **Expected Response:** includes `{ "ready": true }` ## Step 3: Get Presigned Upload URLs Request presigned URLs for your files. If you call `file-upload-urls` before the Data 360 resources are ready, a HTTP status of 400 is returned and you must wait for the `upload-readiness` call in the previous step to indicate readiness before you retry. ```shell FILE_BASENAME=$(basename "$FILE_NAME") RESPONSE=$(curl -s -X POST "$ORG_URL/services/data/v66.0/einstein/data-libraries/$LIBRARY_ID/file-upload-urls" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "files": [ { "fileName": "'"${FILE_BASENAME}"'" } ] }') echo "$RESPONSE" | jq '.' PRESIGNED_URL=$(echo "$RESPONSE" | jq -r '.uploadUrls[0].uploadUrl') FILE_PATH_S3=$(echo "$RESPONSE" | jq -r '.uploadUrls[0].filePath') ``` You get a presigned URL for each file in the `files` array. You can upload a maximum of 1000 files to a library. Pre-signed URLs are available for 15 mins only before they expire. ## Step 4: Upload a File Extract the presigned URL and headers from the creation response, and upload the PDF file. ADL files are stored in a Salesforce-managed S3 bucket in AWS. ```shell UPLOAD_HEADERS=() while IFS='=' read -r key value; do UPLOAD_HEADERS+=(-H "$key: $value") done < <(echo "$RESPONSE" | jq -r '.uploadUrls[0].headers | to_entries[] | "\(.key)=\(.value)"') curl -X PUT "${PRESIGNED_URL}" \ "${UPLOAD_HEADERS[@]}" \ --data-binary @"${FILE_NAME}" \ -w "\nHTTP Status: %{http_code}\n" ``` The presigned URL includes headers. You must parse the header and send it (`UPLOAD_HEADERS`) to S3. **Expected Response:** `HTTP Status: 200` ## Step 5: Trigger Indexing Index the library resources, including the uploaded file. ```shell FILE_SIZE=$(stat -f%z "$FILE_NAME" 2>/dev/null || stat -c%s "$FILE_NAME") curl -s -X POST "$ORG_URL/services/data/v66.0/einstein/data-libraries/$LIBRARY_ID/indexing" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "uploadedFiles": [ { "filePath": "'"${FILE_PATH_S3}"'", "fileSize": '"$FILE_SIZE"' } ] }' | jq '.' ``` **Expected Response:** includes `{ "status": "IN_PROGRESS" }` ## Step 6: Poll Until Ready This command loops every 10 seconds until the status is READY or FAILED. ```shell while true; do STATUS_RESPONSE=$(curl -s "$ORG_URL/services/data/v66.0/einstein/data-libraries/$LIBRARY_ID/status" \ -H "Authorization: Bearer $ACCESS_TOKEN") STATUS=$(echo "$STATUS_RESPONSE" | jq -r '.indexingStatus.status') ALL_STAGES_SUCCESS=$(echo "$STATUS_RESPONSE" | jq -r ' [.indexingStatus.stages[]?.status] | all(. == "SUCCESS") and length > 0') echo "Status: $STATUS | All stages SUCCESS: $ALL_STAGES_SUCCESS" if [ "$STATUS" = "READY" ] || [ "$STATUS" = "FAILED" ] || [ "$ALL_STAGES_SUCCESS" = "true" ]; then echo "$STATUS_RESPONSE" | jq '.' break fi sleep 10 done ``` **Expected:** After a few minutes, the status transitions to `READY`. This script exits when the status is READY, FAILED, or all stages report SUCCESS. The READY status requires chunking/embedding to complete for the SearchIndex. `ALL_STAGES_SUCCESS` means that the ADL pipeline is done even if SearchIndex processing is still pending. After the library is READY or `ALL_STAGES_SUCCESS` is true, you can add more files to the library. ## Step 7: Get Upload URLs for New Files Now, let's see how to add a second file to a library. Update the path for NEW_FILE and run this command block. ```shell NEW_FILE="/Users/yourname/Downloads/file2.pdf" NEW_FILE_BASENAME=$(basename "$NEW_FILE") RESPONSE=$(curl -s -X POST "$ORG_URL/services/data/v66.0/einstein/data-libraries/$LIBRARY_ID/file-upload-urls" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "files": [ { "fileName": "'"${NEW_FILE_BASENAME}"'" } ] }') echo "$RESPONSE" | jq '.' PRESIGNED_URL=$(echo "$RESPONSE" | jq -r '.uploadUrls[0].uploadUrl') FILE_PATH_S3=$(echo "$RESPONSE" | jq -r '.uploadUrls[0].filePath') echo "$PRESIGNED_URL" echo "$FILE_PATH_S3" ``` ## Step 8: Upload the New File ```shell UPLOAD_HEADERS=() while IFS='=' read -r key value; do UPLOAD_HEADERS+=(-H "$key: $value") done < <(echo "$RESPONSE" | jq -r '.uploadUrls[0].headers | to_entries[] | "\(.key)=\(.value)"') curl -X PUT "${PRESIGNED_URL}" \ "${UPLOAD_HEADERS[@]}" \ --data-binary @"${NEW_FILE}" \ -w "\nHTTP Status: %{http_code}\n" ``` **Expected Response:** `HTTP Status: 200` ## Step 9: Register the New File This command adds a second file to the existing file library. It automatically triggers search index re-hydration so you don't need a separate `indexing` call, which you needed for the first file. ```shell NEW_FILE_SIZE=$(stat -f%z "$NEW_FILE" 2>/dev/null || stat -c%s "$NEW_FILE") curl -s -X POST "$ORG_URL/services/data/v66.0/einstein/data-libraries/$LIBRARY_ID/files" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "uploadedFiles": [ { "filePath": "'"${FILE_PATH_S3}"'", "fileSize": '"$NEW_FILE_SIZE"' } ] }' | jq '.' ``` **Expected Response:** includes `{ "filesAccepted": 1 }` Congratulations! You successfully added a second file to your library. # General Agentforce Service Errors These error codes can be returned by any Agentforce service. They represent platform-level conditions that apply across services, such as rate limiting, temporary unavailability, and unexpected system failures. ## INTERNAL_ERROR This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INTERNAL_ERROR` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## NOT_IMPLEMENTED The capability or feature you requested isn't supported by this service. Retrying the same request won't succeed. This error occurs when: - The request asked for a feature or operation this service doesn't support. - A request parameter (such as a model name) uses a value this service doesn't recognize. - An optional capability isn't enabled in your org. ### How to Troubleshoot To resolve this error: 1. Check the documentation for supported capabilities and operations, and confirm your request matches one of them. 2. Review the parameters in your request and correct any unsupported values. 3. If the capability is optional, check that it's enabled in your org's Setup. 4. If the capability you need isn't available in this service, use a different service or operation that supports it. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `NOT_IMPLEMENTED` - What you were trying to do when the error occurred ## RATE_LIMIT_EXCEEDED You've sent more requests than the service allows in the current time window. This request was rejected to keep the service responsive. The limit is temporary and resets shortly. This error occurs when: - A burst of requests was sent in a short period. - Multiple clients sharing the same credentials are sending requests at the same time. ### How to Troubleshoot To resolve this error: 1. Wait at least 10 seconds, then try again. 2. If the error recurs, wait longer before each subsequent attempt. 3. If your workload regularly hits this limit, reduce your request rate or batch work into fewer, larger requests. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `RATE_LIMIT_EXCEEDED` - The approximate request rate you were sending when the error occurred ## SERVICE_TEMPORARILY_UNAVAILABLE The service is temporarily unavailable and isn't accepting requests right now. Your request wasn't processed. This is usually a short-lived issue that resolves on its own. This error occurs when: - The service or a platform dependency it relies on is briefly unavailable. - A spike in traffic temporarily exceeded the service's capacity. ### How to Troubleshoot To resolve this error: 1. Wait at least 5 seconds, then try again once. 2. If the error persists, wait a few minutes before trying again. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `SERVICE_TEMPORARILY_UNAVAILABLE` - What you were trying to do when the error occurred # Generate a Test Spec File **warning:** This section describes the legacy process for testing Agentforce agents, or the pro-code equivalent to using the [Legacy Agentforce Testing Center in Setup](https://help.salesforce.com/s/articleView?id=ai.agent_testing_center_setup_tests.htm&type=5). It doesn't apply to the new agent testing process, or the pro-code equivalent to the [New Testing Center in Agentforce Studio (Beta)](https://help.salesforce.com/s/articleView?id=ai.agent_studio_testing_center_setup_tests.htm&type=5). That documentation will be released soon. A test spec is a YAML file in your DX project that lists the test cases for a particular agent. The test spec file is local to your DX project and is an easy-to-read equivalent of the `AiEvaluationDefinition` metadata component that defines an agent test in your development org. Run this interactive command from the VS Code [integrated terminal](https://code.visualstudio.com/docs/terminal/getting-started) to generate a test spec: ```bash sf agent generate test-spec ``` **tip:** As with all Salesforce CLI commands, you can also generate a test spec by opening a terminal (macOS, Linux) or command prompt (Windows), changing to your DX project directory, and running the `agent generate test-spec` CLI command. The `agent generate test-spec` command first asks you what type of test you want to make; currently, only `AGENT` is supported. It then asks you to select the agent you want to test from a list of agent API names. The command compiles this list by searching your local Salesforce DX project, it doesn't search your org. After you select an agent, the command continues asking for basic information, such as whether you want to overwrite the default file of the test spec if it already exists, and the name and description of the test. The command then prompts you to create one or more test cases by asking you for this information for each test case: - **Utterance** (Required) - A natural-language statement, question, or command to test the agent. Enter utterances that you expect the users of your agent to use. For example: “_Who is working the front desk today at noon?”_ Or “_Send me the list of customer complaints from yesterday.”_ - **Expected subagent** (Required) - The API name of the subagent that you expect the agent to use when it responds to the utterance. The command gets the list of subagents from the local metadata components in your Salesforce DX project that are associated with your agent, specifically GenAiPlugin. - **Expected actions** (Required) - The API name of one or more actions associated with the subagent that you expect the agent to use. The command gets the list of actions from the local metadata components in your Salesforce DX project associated with the subagent, specifically GenAiFunction. - **Expected outcome** (Required) - A natural-language description of the expected outcome of the test case. For example, “_Anna is working the front desk.”_ Or “_The list of customer complaints is provided_.” - **Custom evaluation** (Optional) - A way to test an agent response for specific strings or numbers. See [Add Custom Evaluation Criteria to an Agent Test Spec](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-test-customize.md#add-custom-evaluation-criteria-to-an-agent-test-spec) if you opt to add a custom evaluation to your test. - **Conversation history** (Optional) - Sample conversation history, which adds context to the test. See [Add Conversation History to Enhance the Test Context](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-test-customize.md#add-conversation-history-to-enhance-the-test-context) if you opt to add conversation history to your test. This is an example of a generated test spec file for the `Resort_Manager` agent. By default, the test spec is generated in the `specs` directory and its name is `{Agent_API_name}-testSpec.yaml`. This sample spec file defines one test case: ```yaml name: Resort Manager Tests description: Tests for the Resort Manager agent. subjectType: AGENT subjectName: Resort_Manager testCases: - utterance: Who is working the front desk today at noon? expectedTopic: p_16jQP0000000PEX_Employee_Schedule_Management expectedActions: - EmployeeCopilot__CreateAToDo expectedOutcome: Anna is working the desk. customEvaluations: [] conversationHistory: [] metrics: - completeness - coherence - conciseness - output_latency_milliseconds ``` If you opt to not add custom evaluations or conversation history to the agent test, the `customEvaluations` and `conversationHistory` sections still show up but they're empty. The `agent generate test-spec` command automatically adds the `metrics:` section; see [Use Metrics to Assess Agent Responses](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-test-customize.md#use-metrics-to-assess-agent-responses) for more information about these useful metrics. Now that you understand the structure of the agent spec YAML file, you can manually edit it in the VS Code editor by adding new test cases. ## Generate a Test Spec from an AiEvaluationDefinition Metadata XML File If you have an AiEvaluationDefinition metadata XML file in your DX project, you can make a YAML test spec file from it. You can do this by passing the file path of the XML file to the `--from-definition` flag. This example also shows how to use the `--output-file` flag to specify the name of the spec file: ```bash sf agent generate test-spec \ --from-definition force-app/main/default/aiEvaluationDefinitions/ResortManagerTest.aiEvaluationDefinition-meta.xml \ --output-file specs/Resort_Manager-test-spec.yaml ``` ## See Also - [_Salesforce CLI Command Reference_: agent Commands](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_agent_commands_unified.htm) - [_Salesforce Extensions for Visual Studio Code_](https://developer.salesforce.com/docs/platform/sfvscode-extensions/guide) - [_Salesforce Help_: Agentforce Testing Center](https://help.salesforce.com/s/articleView?id=ai.agent_testing_center.htm&type=5) - [_Reference_: AiEvaluationDefinition](/docs/ai/agentforce/references/testing-api/testing-metadata-reference.html) - [Build Tests in Metadata API](https://developer.salesforce.com/docs/ai/agentforce/testing-api/testing-api-build-tests.md) # Generate an Agent Spec File You optionally use an agent spec file to generate an authoring bundle. Authoring bundles contain the Agent Script file that in turn provides the blueprint of the agent. An agent spec is a YAML-formatted file that contains basic information about the agent, such as its role and details about your company. The spec file also contains an LLM-generated list of subagents based on this information. Subagents define the range of jobs that your agent can handle. While using an agent spec is optional, we recommend that you do it because the Agent Script file in the generated authoring bundle will be more customized for your specific agent. The easiest way to generate an agent spec is to run this command from VS Code’s [integrated terminal](https://code.visualstudio.com/docs/terminal/getting-started). The command prompts you for the required agent properties. ```bash sf agent generate agent-spec --target-org ``` If you’ve set a default development org, such as your sandbox, in your DX project, specifying `--target-org` is optional. **tip:** As with all Salesforce CLI commands, you can also generate an agent spec by opening a terminal (macOS, Linux) or command prompt (Windows), changing to your DX project directory, and running the `agent generate agent-spec` CLI command. The command prompts you for the type of agent, such as customer-facing or internal to your company. It also prompts you for information about the agent’s role and your company. Use natural language for this information, and be thoughtful about your descriptions. The LLM associated with your development org uses the information to generate a list of subagents. The more accurate, specific, and complete your input descriptions are, the better the LLM-generated outputted list of subagents is. After the `agent generate agent-spec` command finishes, the generated agent spec file called `agentSpec.yaml` is in the `specs` sub-directory of your DX project. The structure of the agent spec file is simple. The top part contains the agent properties, including some default ones that you weren’t prompted for. The bottom part contains the LLM-generated list of subagents. See [Agent Spec File Example](#agent-spec-file-example) and [Agent Spec File Reference](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-reference.md). The `agent generate agent-spec` command also has flags that you can use to provide the required and optional agent properties without being prompted, such as `--type`, `--company-description`, `--max-topics`, and `--tone`. In this example, you’re prompted for only the role of the agent because the command uses all the flags except for `--role`: ```bash sf agent generate agent-spec --type customer \ --company-name "Coral Cloud Resorts" \ --company-description "Provide a luxury experience." \ --max-topics 4 --tone formal ``` To show the full list and descriptions of the available flags, run the command with the `--help` flag: ```bash sf agent generate agent-spec --help ``` ## Agent Spec File Example Here’s an example of an agent spec file with the default name (`specs/agentSpec.yaml`) in the `agentforcedx` Salesforce DX project: ![VS Code showing "agentforcedx" DX project in the left explorer panel and a YAML agent spec file in the right editor panel.](https://developer.salesforce.com/media/dx-agent-spec-file-1.png '{"class": "image-full"}') The properties in the top part of the YAML file describe the agent. You initially provided this information to the `agent generate agent-spec` command. Some properties are required, such as `agentType`, `companyName`, and `role`. The list includes optional properties, such as the maximum number of subagents and whether to add agent conversation data to org event logs. The `topics` section contains the list of subagents that the LLM generated based on the agent properties. Each subagent has a `name` and a `description`, both generated by AI. ## Iteratively Generate a Better Agent Spec File If the first time you run `agent generate agent-spec` you're thrilled with the list of LLM-generated subagents, then you're all set. But if you're not, you can use the `--spec` flag to pass the same agent spec file to a new execution of the command, along with improved agent properties, and keep improving the spec. As discussed earlier, the spec file consists of two main sections: the upper part (agent properties) that you provide and the lower part (generated subagents) that the LLM generates. Each time you adjust the agent properties, such as the agent’s role, the list of generated subagents changes, ideally improving with each iteration. By running the command multiple times, and each time passing in the most recent spec and refining the agent properties further, you eventually end up with an agent spec you're satisfied with. Refine the agent properties by either editing the spec file directly or by specifying the appropriate flag, such as `--role`. Let’s see how this works. For example, here’s an initial command run in which the agent information is terse and generic: ```bash sf agent generate agent-spec --type customer \ --company-name "Coral Cloud Resorts" \ --company-description "Provide a luxury experience." \ --role "Manage the resort." --max-topics 3 ``` As a result of not providing many details, the AI-list of subagents might be too broad and not particularly useful. For example: ```yaml topics: - name: Guest Check-In Automation description: Streamline the guest check-in process using AI. - name: Personalized Guest Services description: Provide tailored recommendations and services. - name: Predictive Maintenance description: Use AI to forecast and prevent equipment failures. ``` Rerun the command and embellish the agent role, but specify that you want to keep the other properties the same in the existing spec file (`specs/agentSpec.yaml` by default): ```bash sf agent generate agent-spec --spec specs/agentSpec.yaml --role "Fields customer complaints, manages employee schedules, and generally makes sure everything is working smoothly." ``` The command asks whether you want to overwrite `specs/agentSpec.yaml`, which you do because you’re iteratively refining the file. You can optionally use `--output-file` to create a new agent spec file. And this time, the list of subagents in the spec is better, because you provided a better role description. ```yaml topics: - name: Automated Complaint Resolution description: Utilize AI to resolve customer complaints promptly. - name: Employee Schedule Optimization description: Automatically generate and adjust employee schedules. - name: Luxury Experience Enhancement description: Personalize guest services based on preferences and history. ``` Let’s do more! What if you provide a better company description? ```bash sf agent generate agent-spec --spec specs/AgentSpec.yaml --company-description "Provides customers with exceptional destination activities, unforgettable experiences, and reservation services, all backed by a commitment to top-notch customer service." ``` You can iterate this way as much as you want and end up with the perfect agent spec file. ## Tips and Gotchas - When you run `agent generate agent-spec`, focus on providing the most accurate, specific, and complete descriptions about your company, the role of the agent, and so on. Better descriptions result in a better LLM-generated list of subagents. - Because the agent spec file is in YAML format, it’s easy to edit manually in the VS Code editor after you creat an initial file. You must, however, rerun `agent generate agent-spec` to get a new set of AI-generated subagents. - When you create an agent using the agent spec file (described later), the LLM associated with your development org generates an initial list of actions and instructions based on the spec. You can add natural language hints directly in the subagent descriptions to help the LLM come up with a good list. For example, you can tell the LLM to use only a specific action that you know exists in your org: ```yaml topics: - name: Local Events description: Provide information about the local activities and events. Use only the "Check_Events" action for this subagent. ``` ## Next Step - [Generate an Authoring Bundle](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-nga-authbundle.md) ## See Also - [_Salesforce CLI Command Reference_: agent Commands](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_agent_commands_unified.htm) - [_Salesforce Extensions for Visual Studio Code_](https://developer.salesforce.com/docs/platform/sfvscode-extensions/guide) # Generate an Authoring Bundle An important step in authoring an agent from scratch in your DX project is to generate its authoring bundle. An authoring bundle defines the blueprint for an agent. Specifically, authoring bundles are metadata types (named `AiAuthoringBundle`) that contain the agent's Agent Script file. The Agent Script file has the extension `.agent` and is written using the [Agent Script language](https://developer.salesforce.com/docs/ai/agentforce/agent-script/agent-script.md). See [Authoring Bundle Metadata](/docs/ai/agentforce/references/agents-metadata-tooling/agents-metadatav67.html) for more details about this metadata type. **tip:** Because an _agent_ is defined by its _authoring bundle_, this documentation and the Agentforce DX tools use the two terms interchangeably. For example, the CLI command discussed in this topic uses the term _authoring bundle_, such as `agent generate authoring-bundle`. However, the equivalent VS Code command uses the term _agent_, such as **AFDX: Create Agent**. While not required, you can first generate an agent spec YAML file which you can then specify when you generate an authoring bundle. Because the agent spec file contains your subagents, the generated Agent Script file in the authoring bundle is more customized for your new agent. If you don't use an agent spec file, then the generated authoring bundle contains the default Agent Script boilerplate. If you're just starting on your Agent Script journey, we recommend that you use the default boilerplate. But if you're more advanced, try generating and using an agent spec YAML first. See [Generate an Agent Spec File](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-generate-agent-spec.md). After you finish generating the authoring bundle, the new `*.agent` file contains basic Agent Script code to get you started. If you specified an agent spec file, then some of the code is generated from its list of subagents. The authoring bundle is generated in the `aiAuthoringBundles/` directory of your package directory, such as `force-app/main/default/aiAuthoringBundles/My_Bundle`. The directory contains, for example, the `My_Bundle.agent` and `My_Bundle.bundle-meta.xml` files. ## Use VS Code to Generate an Authoring Bundle 1. In VS Code, open your Salesforce DX project and be sure you've authorized your development org. 1. From VS Code Command Palette, run the **AFDX: Create Agent** command. You can also run this command by right-clicking the `aiAuthoringBundles` directory in your package directory, as long it exists in your DX project. The Agentforce DX panel also has a **Create Agent** button. 1. Select the template used to generate the authoring bundle. - **Default template (Recommended)**: Starts with a basic boilerplate Agent Script file. - **From an agent spec YAML file (Advanced)**: This option shows up only if there's at least one agent spec YAML file in the `specs` directory in your DX project. If you select this option, you're then asked to select the specific agent spec YAML file you want to use. 1. Enter the name (label) of your new authoring bundle. You can use spaces in the name (label). 1. Enter the API name of the bundle. We recommend that you use the default that's displayed. The default value for the authoring bundle's API name is derived from the label. For example, if you entered `My Bundle` for the label, then its default API name is `My_Bundle`. ## Use a CLI Command to Generate an Authoring Bundle 1. In VS Code, open the integrated terminal. Be sure you've authorized your development org. You can also open a terminal (macOS/Linux) or command prompt (Windows) and change to your Salesforce DX project. 1. Run this command: ```bash sf agent generate authoring-bundle ``` 1. Select the template used to generate the authoring bundle. - **Default template (Recommended)** : Starts with a basic boilerplate Agent Script file. - **From an agent spec YAML file (Advanced)** : This option shows up only if there's at least one agent spec YAML file (with a name that ends in `AgentSpec.yaml`) in the `specs` directory in your DX project. If you select this option, you're then asked to select the specific agent spec YAML file you want to use. 1. Enter the name (label) of your new authoring bundle. You can use spaces in the name (label). 1. Enter the API name of the bundle. We recommend that you use the default that's displayed. The default value for the authoring bundle's API name is derived from the label. For example, if you entered `My Bundle` for the label, then its default API name is `My_Bundle`. You can specify many of the values with flags, such as `--spec`, `--name`, and `--api-name`. If you haven't set a default org in your project, use the `--target-org` flag to specify the org's username or alias. Use the `--no-spec` flag to skip prompting for a template and use the default boilerplate Agent Script file instead. For example: ```bash sf agent generate authoring-bundle --no-spec --name "My Bundle" --api-name My_Bundle --target-org my-dev-org ``` ## Next Step - [Code Your Agent Using Its Script File](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-nga-script.md) ## See Also - [Set Up Your Development Environment for Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-set-up-env.md) - [Generate an Agent Spec File](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-generate-agent-spec.md) - [Agentforce Metadata Types](/docs/ai/agentforce/references/agents-metadata-tooling/agents-metadatav67.html) - [_Salesforce CLI Command Reference_: agent Commands](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_agent_commands_unified.htm) # Generate OpenAPI and Metadata Documents and Configure an Agent Action Follow these steps to create your first OpenAPI document. Use the sample Apex REST class and the generated files that we’re providing to quickly learn about the workflow. If you prefer, you can use one of the Apex REST classes you retrieved. ## Generate the Files 1. In VS Code or Agentforce Vibes IDE, open the Command Palette (⇧⌘P) and run the command **SFDX: Create Project** command to create a new Salesforce project. 2. Run **SFDX: Set a Default Org** to select the org to which you want to deploy the new OAS. 3. If you aren’t using a class you retrieved, run **SFDX: Create Apex Class** to create a new Apex class. For example, create a class called `CaseManager`. 4. Write your Apex class using [Apex REST annotations](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_rest_annotations_list.htm). For example, you can copy this code and paste it into the `CaseManager.cls` file that you just created. ``` @RestResource(urlMapping='/apex-rest-examples/v1/Cases/*') global with sharing class CaseManager { @HttpGet global static Case getCaseById() { RestRequest request = RestContext.request; // grab the caseId from the end of the URL String caseId = request.requestURI.substring( request.requestURI.lastIndexOf('/')+1); Case result = [SELECT CaseNumber,Subject,Status,Origin,Priority FROM Case WHERE Id = :caseId]; return result; } @HttpPost global static ID createCase(String subject, String status, String origin, String priority) { Case thisCase = new Case( Subject=subject, Status=status, Origin=origin, Priority=priority); insert thisCase; return thisCase.Id; } @HttpDelete global static void deleteCase() { RestRequest request = RestContext.request; String caseId = request.requestURI.substring( request.requestURI.lastIndexOf('/')+1); Case thisCase = [SELECT Id FROM Case WHERE Id = :caseId]; delete thisCase; } @HttpPut global static ID upsertCase(String subject, String status, String origin, String priority, String id) { Case thisCase = new Case( Id=id, Subject=subject, Status=status, Origin=origin, Priority=priority); // Match case by Id, if present. // Otherwise, create new case. upsert thisCase; // Return the case ID. return thisCase.Id; } @HttpPatch global static ID updateCaseFields() { RestRequest request = RestContext.request; String caseId = request.requestURI.substring( request.requestURI.lastIndexOf('/')+1); Case thisCase = [SELECT Id FROM Case WHERE Id = :caseId]; // Deserialize the JSON string into name-value pairs Map params = (Map)JSON.deserializeUntyped(request.requestbody.tostring()); // Iterate through each parameter field and value for(String fieldName : params.keySet()) { // Set the field and value on the Case sObject thisCase.put(fieldName, params.get(fieldName)); } update thisCase; return thisCase.Id; } } ``` 5. Run **SFDX: Refresh SObjects Definitions** to bring org metadata in the form of object definitions into your project. Select All SObjects. 6. Run **SFDX: Create OpenAPI Document from this Class** from the command palette or the context menu. 7. Enter the folder where you want to store the generated files or accept the default `externalServiceRegistration` folder. The command generates the files `.yaml`, and `.externalServiceRegistration-meta.xml`. **note:** The description that appears in your org's API catalog comes from the top-level description mapping in the YAML file, not the `` element of the XML file. 8. To verify the validity of the generated YAML and XML files, see [Verify Metadata and OpenAPI Documents](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-apex-verify-spec.md). Also, check the Problems in the Panel bar for error messages and warnings and fix the generated files as needed. 9. Run **SFDX: Validate OpenAPI Document** on the corrected YAML file to ensure all the errors and warnings are gone. **note:** If the MuleSoft for Agentforce Extension Pack is installed, then **SFDX: Validate OpenAPI Document** isn’t available. Use the governance rules in the MuleSoft for Agentforce Extension Pack to validate your OpenAPI document. For details, see [Verify Metadata and OpenAPI Specification Documents](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-apex-verify-spec.md). 10. Run the **SFDX: Deploy This Source to Org** command to deploy the `CaseManager.cls` class , or the class you’re working with, to your org. 11. Next deploy the generated XML file to the org. Note that the command to deploy isn't ‌available on the YAML file. ### Regenerate OpenAPI Documents You can regenerate an OpenAPI document if you modify the Apex class associated with it: 1. Make the changes to the Apex class associated with the OpenAPI document. 2. Run the **SFDX: Create OpenAPI Document from this Class** command. 3. Select **Overwrite** or **Manually merge with existing ESR** the popup window. **Overwrite** directly overwrite the existing OpenAPI document (This action is irreversible). The **Manually Merge with Existing ESR** option opens a diff window comparing the original and new OpenAPI documents. The new files are generated with the naming format: `_.externalServiceRegistration-meta.xml` and `_.yaml`.These files are located in the `esr_files_for_merge` folder in the root directory of your Salesforce project. 4. Check the Problems tab for any errors or warnings in the new OpenAPI document (identified by the timestamp) and manually merge the changes from the newly generated OpenAPI document into the original document. 5. Run the **SFDX: Validate OpenAPI Document** command on the merged or overwritten OpenAPI document. 6. Deploy the validated OpenAPI document to your Salesforce org. **note:** You may encounter API Catalog limits when deploying. See [Limits](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-apex-limits.md). ## Confirm the Availability of the Agent Action Once deployed, your API and its operations are available in your org's API catalog. 1. From Setup, in the Quick Find box, enter API Catalog and select it. See [View Apex APIs in API Catalog](https://help.salesforce.com/s/articleView?id=platform.api_catalog_view_apex_apis.htm&type=5). 2. Click the Apex tab. The deployed API is listed. ![Apex tab in API catalog](https://developer.salesforce.com/media/api-catalog-apex.png '{"class": "image-full image-framed"}') 3. The API and its operations are now available as an Apex Reference Action type that can be used to [Create a Custom Agent Action](https://help.salesforce.com/s/articleView?id=ai.copilot_actions_custom_create_scratch.htm&type=5). ![Create agent action in agentforce builder](https://developer.salesforce.com/media/agent-builder-action-apex.png '{"class": "image-xxl image-framed"}') # Generate with Models API The generative endpoints of the Models API connect your application to large language models (LLMs) from Salesforce partners, including Anthropic, Google, and OpenAI. Use these endpoints to generate chat responses, embeddings, and text from a prompt. ## Capabilities - **Generate Chat** — Generate a response based on a list of messages representing a chat conversation. - **Generate Embeddings** — Create an embedding vector representing the input text. - **Generate Text** — Generate a response based on a single prompt. - **Submit Feedback** — Send feedback on generated content to Data 360. ## Access - [Access Models API with Apex](https://developer.salesforce.com/docs/ai/agentforce/guide/access-models-api-with-apex.md) - [Access Models API with REST](https://developer.salesforce.com/docs/ai/agentforce/guide/access-models-api-with-rest.md) - [LWC & Flow Examples](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api-build-lwc-flow.md) ## Considerations - [Generation Feedback](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api-feedback.md) - [Language & Locales](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api-languages-and-locales.md) - [Data Masking](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api-data-masking.md) - [Toxicity Scoring](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api-toxicity-scoring.md) # Get Started with ADL API This guide shows you how to work with Connect REST API resources to manage Agentforce data libraries (ADL). ## Prerequisites There are a few tools and items that we need for this quick start. The instructions focus on macOS and Linux but they should work with minimal changes on a different OS. ### Salesforce CLI Salesforce CLI is a command-line interface that simplifies development and build automation when working with your Salesforce org. We use it to authenticate and get information about an org. Install the CLI by using the [Salesforce CLI Setup Guide](https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli.htm#sfdx_setup_install_cli_macos). ### jq We use jq for parsing JSON. To see if jq is already installed on your computer, run: `jq --version` If jq isn’t installed, run: `brew install jq` ### PDF File You need a PDF on your machine. The content doesn't matter. We use the PDF as a file in your first data library. ### Test Org Set up an org for the quick start. For org requirements, see [Setting Up Data Libraries](https://help.salesforce.com/s/articleView?id=ai.data_library_setup.htm&type=5) in Salesforce Help. ### Create an External Client App To securely use Connect API endpoints for ADL, you must create an [External Client App (ECA)](https://help.salesforce.com/s/articleView?id=xcloud.external_client_apps.htm&type=5). Create an external client app with OAuth and usage of a JWT access token enabled. Use these instructions to get set up: [Create a Local External Client App](https://help.salesforce.com/s/articleView?id=xcloud.create_a_local_external_client_app.htm&type=5) When creating the app, include these settings. 1. Use these OAuth Scopes: - **Access Connect REST API Resources (chatter_api)** - **Manage user data via APIs (api)** - **Manage user data via Web browsers (web)** - **Perform requests at any time (refresh_token, offline_access)** ![OAuth scopes settings](https://developer.salesforce.com/media/testing-eca-oauth.png) 2. Select these additional OAuth settings: - **Enable Client Credentials Flow** - **Issue JSON Web Token (JWT)-based access tokens for named users** ![OAuth flow and security settings](https://developer.salesforce.com/media/testing-eca-oauth-flow.png '{"class": "image-md"}') - For more information on OAuth settings and security, see [Configure the External Client App OAuth Settings](https://help.salesforce.com/s/articleView?id=xcloud.configure_external_client_app_oauth_settings.htm&language=en_US&type=5). 3. After creating the app, make sure that the API caller has the correct client credentials and that the client can issue JWT-based access tokens. - Click the **Policies** tab for the app, and then click **Edit**. - Select the **Enable Client Credentials Flow** checkbox. - Specify the client user in the **Run As** field. - Select the **Issue JSON Web Token (JWT)-based access tokens** checkbox. By default, this token expires in 30 minutes. You can change this value to less than 30 minutes. ### Get Credentials To create a token, you need the consumer key and the consumer secret from your ECA. 1. From Setup, find and select **External Client Apps**. 2. Select your app and click the **Settings** tab. 3. Expand the **OAuth Settings** section. 4. Click the **Consumer Key and Consumer Secret** button, and copy your secrets. You need these values to mint this token. 5. **Important:** Store your consumer secret in a secure location. 6. From Setup, in the Quick Find box, enter `My Domain`, and then select **My Domain**. 7. Copy the value shown in the **Current My Domain URL** field. 8. Request a JWT access token from Salesforce by using a POST request, specifying the values for your consumer key, consumer secret, and domain name. ### Get an Access Token All calls to Connect API require an access token. Create a token by using the consumer key, the consumer secret, and your domain name. For more information, see the [Connect REST API Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/quickstart_connecting.htm). In a Terminal, set these environment variables after you replace `{CONSUMER_KEY}`, `{CONSUMER_SECRET}`, and `{MY_DOMAIN_URL}` with values from your org. - `MY_DOMAIN_URL`: Get the domain from Setup by searching for **My Domain**. Copy the value shown in the **Current My Domain URL** field. - `CONSUMER_KEY`, `CONSUMER_SECRET`: Get the consumer key and secret by following the instructions in Get Credentials. ``` export SF_CLIENT_ID={CONSUMER_KEY} export SF_CLIENT_SECRET={CONSUMER_SECRET} export SF_INSTANCE_URL=https://{MY_DOMAIN_URL}.my.salesforce.com ``` Run this command block to get an access token. ``` # Get token via client_credentials flow RESPONSE=$(curl -s -X POST \ "$SF_INSTANCE_URL/services/oauth2/token" \ -d "grant_type=client_credentials" \ -d "client_id=$SF_CLIENT_ID" \ -d "client_secret=$SF_CLIENT_SECRET") ACCESS_TOKEN=$(echo $RESPONSE | jq -r '.access_token') ORG_URL=$(echo $RESPONSE | jq -r '.instance_url') # Verify ADL API curl -s "$INSTANCE_URL/services/data/v66.0/einstein/data-libraries" \ -H "Authorization: Bearer $ACCESS_TOKEN" | jq '.' ``` If you get a JSON response (even an empty array), OAuth is working. ### Set Up Shell Variables Copy and paste this block into your terminal. It sets up a unique library name for your session. Update `FILE_NAME` to point to your test PDF. ```shell # Generate a unique library name ADL_PREFIX="your_prefix" ADL_SUFFIX=$(date +%m%d)_$(LC_ALL=C tr -dc 'a-z0-9' < /dev/urandom | head -c3) ADL_DevName="${ADL_PREFIX}_${ADL_SUFFIX}" ADL_Name="${ADL_PREFIX} ${ADL_SUFFIX}" # Point to your test file (change this path) FILE_NAME="/Users/yourname/Downloads/file1.pdf" ``` We're using a specific library naming convention for this quick start. You can choose any naming scheme for your libraries. # Get Started with Agent Script Get to know the language for building agents in Agentforce Builder. Use Agent Script to build predictable, context-aware agent workflows that don't rely solely on interpretation by an LLM. **note:** Beginning in April 2026, agent **topics** are now called **subagents**. There are no changes to functionality. During this transition, you may see a mix of the new and previous terms in our documentation To get hands-on with Agent Script, [Create an Agent](https://help.salesforce.com/s/articleView?id=ai.agent_setup_create.htm&type=5), then select **Script** from the view picker. Or, author an agent with [Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/agent-dx/agent-dx-nga-author-agent.md). ![Agent Script UI](https://developer.salesforce.com/media/agent-script/agent-script-view3.png) ## What's Agent Script? Agent Script is the language for building agents in Agentforce Builder. Script combines the flexibility of natural language instructions for handling conversational tasks with the reliability of programmatic expressions for handling business rules. In script, you use expressions to define if/else conditions, transitions, and other logic; set, modify, and compare variables; and select subagents and actions. You can build predictable, context-aware agent workflows that don’t rely solely on interpretation by an LLM. For example, you can use script to control when your agent transitions from one subagent to another or when actions are run in a particular sequence (sometimes called action chaining). Agentforce Builder gives you several ways to write Agent Script. - You can chat with Agentforce and explain what you want your agent to be able to do (for example, "If the order total is over \$100, then offer free shipping."). Agentforce converts your request into subagents, actions, instructions, and other expressions. - In Canvas view, Agent Script is summarized into easily understandable blocks, which you can expand to view the underlying script. You can edit your agent with the help of quick action shortcuts. Type `/` to add expressions for common patterns (for example, if/else conditionals) and `@` to add resources (subagents, actions, and variables). - Advanced users can switch to Script view to write and edit script directly, with developer-friendly aids like syntax highlighting, autocompletion, and validation. Developers can also use Agentforce DX to generate or retrieve a script file into their local Salesforce DX project and then work with it in Visual Studio Code. The Agentforce DX VS Code Extension fully supports the Agent Script language with standard code editing features. See [Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/agent-dx/agent-dx.md) for more details. ## What Can You Do with Agent Script? Agent Script preserves the conversational skills and complex reasoning ability derived from natural language prompts, and it adds the determinism of programmatic instructions. For example, in Agent Script, you can define: - Specific areas where an LLM is free to make reasoning decisions. See [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-instructions.md). - Specific areas where the agent must execute deterministically. See [Reasoning Instructions](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-instructions.md). - Variables to reliably store information about the agent's current state, rather than relying on LLM context memory. See [Variables](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-variables.md). - Conditional expressions to determine the agent's execution path or LLM's utterances. For example, you can instruct the agent to speak differently to the customer based on the value of the `is_member` variable. Or you can deterministically specify which action to run based on the value of the `appointment_type` variable. See [Conditional Expressions](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-expressions.md). - Conditions under which the agent transitions to a new subagent. You can deterministically transition to a new subagent. Or you can expose a subagent transition to the LLM as a tool, allowing the LLM to decide when and whether to switch subagents. See [Tools](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-tools.md) and [Utils](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-ref-utils.md). ## Example Agent Script Here’s a simple example of what Agent Script looks like. ```agentscript system: instructions: "You are a friendly and empathetic agent that helps customers with their questions." messages: error: "Sorry, something went wrong." welcome: "Hello! How are you feeling today?" config: agent_name: "HelloWorldBot" access: default_agent_user: "agent_user1@mycompanyname.com" language: default_locale: "en_US" additional_locales: "" variables: isPremiumUser: mutable boolean = False description: "Indicates whether the user is a premium user." start_agent hello_world: description: "Respond to the user." reasoning: instructions: -> if @variables.isPremiumUser: | ask the user if they want to redeem their Premium points else: | ask the user if they want to upgrade to Premium service ``` Among other compelling features, you can see in the above reasoning instructions that you can specify conditional logic (after the `->`) alongside LLM prompts (after the `|`). This combination gives you the advantages of predictable, deterministic logic, alongside the power of LLM reasoning. ## Agent Skills Want to build Agent Script agents using an agent skill or with Agentforce Vibes? Check out these resources! - [Skills in Agentforce Vibes](https://developer.salesforce.com/docs/platform/einstein-for-devs/guide/skills.html) — A page describing how skills are used with Agentforce Vibes. - [Salesforce Skills Library](https://github.com/forcedotcom/afv-library) — A curated collection of Salesforce agent skills for building applications using any AI tool that supports skills. - [Agentforce Development Skill](https://github.com/forcedotcom/afv-library/tree/main/skills/developing-agentforce) — The specific skill (located within the Agentforce Vibes Library) designed for building, modifying, debugging, and deploying Agentforce agents using Agent Script. ## Next Steps To learn how to build agents in Canvas view or by chatting with Agentforce, see [Build Enterprise-Ready Agents with the New Agentforce Builder](https://help.salesforce.com/s/articleView?id=ai.agent_builder_intro.htm) in Salesforce Help. To learn more about Agent Script, review these topics. - [Language Characteristics](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-lang.md) - [Agent Script Blocks](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-blocks.md) - [Flow of Control](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-flow.md) - [Agent Script Patterns](https://developer.salesforce.com/docs/ai/agentforce/guide/patterns/ascript-patterns.md) - [Agent Script Examples](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-examples.md) - [Agent Script Reference](https://developer.salesforce.com/docs/ai/agentforce/guide/reference/ascript-reference.md) ## See Also - [Manage Agent Script Agents](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-manage.md) - _Trailhead_: [Programmatic Instructions in Agentforce](https://trailhead.salesforce.com/content/learn/modules/programmatic-instructions-in-agentforce) - _Trailhead_: [Agent Script Basics](https://trailhead.salesforce.com/content/learn/modules/agent-script-basics) # Get Started with Agentforce and AI Agents Agentforce is the agent-driven layer of the Salesforce Platform, and it helps you deploy AI agents that work side-by-side with your employees to extend your workforce and serve customers 24/7. The Trust Layer securely connects your data with the power of large language models (LLMs). This guide provides all the information that you need to develop with Agentforce and generative AI. ## Develop with Agentforce Develop Agentforce agents using our APIs, SDKs, and agentic solutions. **Build and Integrate Agents** - [Agentforce APIs and SDKs](https://developer.salesforce.com/docs/ai/agentforce/guide/agentforce/get-started-agents.md): Learn how to use various APIs and SDKs to build powerful Agentforce solutions - [Agentforce Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/agentforce/get-started-actions.md): Learn how to build and enhance your Agentforce actions - [Agent Script](https://developer.salesforce.com/docs/ai/agentforce/guide/agentforce/agent-script/agent-script.md): Learn how to use the language for building agents in Agentforce Builder - [Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/guide/agentforce/agent-dx/agent-dx.md): Learn how to use pro-code Agentforce tools for Salesforce CLI and VS Code - [Download Agent Script Documentation](https://developer.salesforce.com/docs/ai/agentforce/guide/agentforce/agent-script/ascript-download-documentation.md): Get Agent Script docs as markdown files to ground your AI coding tools **Develop Headlessly** - [Headless Agentforce Development](https://developer.salesforce.com/docs/ai/agentforce/guide/headless/headless.md): Build, deploy, test, and operate agents from your IDE, AI coding tool, or CI/CD system without using the platform UI - [Headless Development Tools](https://developer.salesforce.com/docs/ai/agentforce/guide/headless/headless-tools.md): Choose between Agentforce Vibes, third-party AI coding tools, Salesforce CLI, Agent Script, and APIs - [MCP Solutions](https://developer.salesforce.com/docs/ai/agentforce/guide/mcp.md): Connect AI applications and coding tools to Salesforce through Model Context Protocol servers - [Agentforce Vibes](https://developer.salesforce.com/docs/ai/agentforce/guide/vs-code-extension.md): Develop with Salesforce's AI-powered Visual Studio Code extension - [Plugins and Skills](https://developer.salesforce.com/docs/ai/agentforce/guide/agentforce/skills-plugins/skills-plugins.md): Ground AI coding tools with reusable Agentforce development workflows - [Build and Deploy the Palonia Resort Demo with a Coding Agent](https://developer.salesforce.com/docs/ai/agentforce/guide/agentforce/agent-examples/headless-example-org-build.md): Use an AI coding assistant to build and deploy an end-to-end Agentforce solution to a Salesforce org ## Develop with Models and Prompts The Salesforce Platform provides you with some powerful tools to configure and use large language models (LLMs). You can also use Prompt Builder features to create, manage, and use your prompt templates. - [Get Started with Models and Prompts](https://developer.salesforce.com/docs/ai/agentforce/guide/models/models-get-started.md) ## See Also - _Salesforce Help_: [Agentforce and Generative AI](https://help.salesforce.com/s/articleView?id=ai.generative_ai.htm) - _Salesforce Help_: [Agentforce Agents](https://help.salesforce.com/s/articleView?id=ai.copilot_intro.htm) # Get Started with Agentforce APIs and SDKs Bring the power of conversational AI to your business with Agentforce agents. Build a trusted and customizable AI assistant that empowers your users to get more done in Salesforce. Accelerate your Agentforce integration with our APIs and other developer resources. **note:** Beginning in April 2026, agent **topics** are now called **subagents**. There are no changes to functionality. During this transition, you may see a mix of the new and previous terms in our documentation | Feature or API | Description | Build Agents | Test Agents | Use Agents | | ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------- | ------------ | ----------- | ---------- | | [Agent Script](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-script/agent-script.md) | Scripting language for building agents with natural language and programmatic control | Yes | | | | [Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx/agent-dx.md) | Pro-code tools for Salesforce CLI and VS Code | Yes | Yes | Yes (\*) | | [Agentforce Python SDK](https://github.com/salesforce/agent-sdk/tree/main) | Programmatic agent creation and management | Yes | | | | [Testing API](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api/testing-api-get-started.md) | Programmatic test automation | | Yes | | | [Agent API](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api/agent-api-get-started.md) | Chat with agents via REST API | | | Yes | | [Custom Connections](https://developer.salesforce.com/docs/ai/agentforce/guide/custom-connections/custom-connections.md) | Connect external chat clients to the Agent API with structured response formats | | | Yes | | [Agentforce Mobile SDK](https://developer.salesforce.com/docs/agentforce-mobile-sdk/guides/agentforce-mobile-sdk.md) | Integrate Agentforce into your mobile app | | | Yes | | [Enhanced Chat v2](https://developer.salesforce.com/docs/ai/agentforce/guide/enhanced-chat/get-started-enhanced-chat.md) | Create customer-facing web chat experiences in Service Cloud | | | Yes | | [Enhanced In-App Chat SDK](https://developer.salesforce.com/docs/service/messaging-in-app/guide/introduction.html) | Create and customize Service Cloud-based chat experiences in mobile apps | | | Yes | | [ADL API](https://developer.salesforce.com/docs/ai/agentforce/guide/adl/adl.md) | Create and manage data libraries programmatically | | | | | [Export Session Tracing Data](https://developer.salesforce.com/docs/ai/agentforce/guide/session-tracing/otel-api.md) | Extract a single, unified JSON view of a full agent session trace | | | | (\*) Agentforce DX provides the `agent preview` Salesforce CLI command, which you can use to interact with an active agent for testing purposes. **note:** Looking for developer solutions to build and enhance Agentforce actions? See [Build and Enhance Agentforce Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/get-started-actions.md). ## Build Agents Build agents programmatically using Agentforce developer tools. For information about the underlying agent metadata structure, see [Agentforce Metadata Types](/docs/ai/agentforce/references/agents-metadata-tooling/agents-metadatav67.html). ### Build Agents Using Agent Script Agent Script is the language for building agents in Agentforce Builder. Script combines the flexibility of natural language instructions for handling conversational tasks with the reliability of programmatic expressions for handling business rules. In script, you use expressions to define if/else conditions, transitions, and other logic; set, modify, and compare variables; and select subagents and actions. You can build predictable, context-aware agent workflows that don’t rely on interpretation by an LLM. - [Get Started with Agent Script](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-script/agent-script.md) ### Build Agents Using Agentforce DX Use pro-code tools such as Salesforce CLI and VS Code to create and manage agents. - [Build Agents with Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx/agent-dx.md) ### Build Agents with Agentforce Python SDK The Agentforce Python SDK provides a programmatic way to create, manage, and deploy AI agents in Salesforce. - [Agentforce Python SDK Reference](https://github.com/salesforce/agent-sdk/tree/main) ## Test Agents Use Testing API, Agentforce DX, or the Testing Center to test your Agentforce agents. | Feature Name | Access Method | Test Definition Format | [Custom Evaluations Support](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api//testing-api-custom-evaluation-criteria.md) | Description | | ---------------------------------------------------------------------------------------------- | ------------- | ---------------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [**Testing Center**](https://help.salesforce.com/s/articleView?id=ai.agent_testing_center.htm) | UI | CSV | No | Generate and run tests through the Salesforce UI. | | [**Agentforce DX**](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx/agent-dx-test.md) | Command Line | YAML | Yes | Salesforce CLI extension that can author, deploy, and run agent test specifications. | | [**Testing API**](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api/testing-api-build-tests.md) | Code | XML | Yes | Direct API access using [Metadata API](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_types_list) and [Connect API](https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/intro_what_is_chatter_connect.htm). | ## Chat with Agents Chat with AI agents programmatically and deploy customer-facing use cases. ### Chat with Agents Using Agent API Use the Agent API to communicate with AI agents directly from an API. Start sessions, send messages to the AI agent, receive messages, and end sessions with the API. - [Get Started with Agent API](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api/agent-api-get-started.md) You can also access an invocable action to chat with an agent. See [Calling an Agent from a Flow or Apex Class](https://help.salesforce.com/s/articleView?id=ai.agent_custom_invocable_action_flow_apex.htm) in Salesforce Help. ### Chat with Agents Using Enhanced Chat For Service Cloud use cases, you can connect and deploy Service agents to external chat channels. Enhanced Chat v2 provides Javascript web APIs to pass context events. - [Get Started With Enhanced Chat v2](https://developer.salesforce.com/docs/ai/agentforce/guide/enhanced-chat/get-started-enhanced-chat.md) ## Integrate Agents into Mobile Apps Integrate AI agents into your customer-facing mobile app with an SDK. ### Integrate Agents Using the Agentforce Mobile SDK The Agentforce Mobile SDK empowers you to integrate Salesforce's feature-rich, trusted AI platform directly into your native iOS and Android mobile applications. By leveraging the Agentforce Mobile SDK, you can deliver cutting-edge, intelligent, and conversational AI experiences to your mobile users, enhancing engagement and providing seamless access to information and actions. - [Get Started with Agentforce Mobile SDK](https://developer.salesforce.com/docs/agentforce-mobile-sdk/guides/agentforce-mobile-sdk-overview.md) ### Integrate Agents Using the Enhanced In-App Chat SDK The Enhanced In-App Chat SDK enables you to deliver a modern, highly customizable messaging experience directly inside your native mobile applications. You can connect and deploy Service agents to external chat channels for Service Cloud use cases. Its human-in-the-loop design enables seamless escalation from Agentforce agent to human service rep with full conversation context. - [Get Started with Enhanced In-App Chat](https://developer.salesforce.com/docs/service/messaging-in-app/guide/introduction.html) ## Build and Enhance Agentforce Actions Actions are the building blocks that enable your Agentforce agents to perform tasks and interact with data. You can create custom actions to extend your agent's capabilities and enhance the user experience with rich interfaces and detailed responses. - [Build and Enhance Agentforce Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/get-started-actions.md) ## See Also - _Salesforce Help_: [Agentforce Agents](https://help.salesforce.com/s/articleView?id=ai.copilot_intro.htm) - _Salesforce Help_: [Agent Actions](https://help.salesforce.com/s/articleView?id=ai.copilot_actions.htm) - _Trailhead_: [Agents and Agentforce Basics](https://trailhead.salesforce.com/content/learn/modules/einstein-copilot-basics) # Get Started with AI Models With [AI Models](https://help.salesforce.com/s/articleView?id=data.c360_a_ai_use_ai_models.htm) (formerly Einstein Studio), you can configure foundation models, customize model hyperparameters, and test prompts in a playground environment before deploying a model to production. See [Configure and Test a Model with Model Playground](https://help.salesforce.com/s/articleView?id=data.c360_a_ai_foundation_models_test.htm). You can also bring your own large language model (BYOLLM) from an LLM provider using your own account. The model is saved to the Model Library in AI Models as a foundation model that you can configure. See [Add a Foundation Model](https://help.salesforce.com/s/articleView?id=data.c360_a_ai_foundation_models_create.htm) and [Bring Your Own LLM](https://developer.salesforce.com/docs/ai/agentforce/supported-models.md#bring-your-own-llm). To connect _any_ language model (including custom-built models) to the BYOLLM feature in AI Models, you can use the LLM Open Connector. The [Einstein AI Platform GitHub repository](https://github.com/salesforce/einstein-platform) contains API specifications and example code for the LLM Open Connector. When you’re familiar with how to configure and manage your models with AI Models, you can access these models using the Models API. ## Access Your Models Programmatically Access your AI Models generative models with the Models API. - [Access Models API with REST](https://developer.salesforce.com/docs/ai/agentforce/models-api/access-models-api-with-rest.md) - [Access Models API with Apex](https://developer.salesforce.com/docs/ai/agentforce/models-api/access-models-api-with-apex.md) - [Supported Models](https://developer.salesforce.com/docs/ai/agentforce/supported-models.md) - [Build Lightning Web Components and Flows with Models API](https://developer.salesforce.com/docs/ai/agentforce/models-api/models-api-build-lwc-flow.md) ## See Also - _Salesforce Help_: [Use AI Models](https://help.salesforce.com/s/articleView?id=data.c360_a_ai_use_ai_models.htm) - Einstein AI Platform on GitHub: [LLM Open Connector](https://github.com/salesforce/einstein-platform?tab=readme-ov-file#llm-open-connector) # Get Started with Citations in Apex These Apex classes enable developers to add citations to a custom action programmatically. To add citations to a custom action, you’ll need to implement it with an Apex class. Citations can be consumed via employee agents as well as through calls to the [Agent API](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api.html). For more information on citations for employee agents and Knowledge Action, see [Build Trust in AI Responses with Citations](https://help.salesforce.com/s/articleView?language=en_US&id=ai.generative_ai_trust_citations.htm) in Salesforce Help. **important:** Platform-generated citations are only available for agents created after May 26, 2025. ## Prerequisites This guide assumes you have experience developing Apex custom actions. For more information, review these guides: - [Apex Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_dev_guide.htm) - [Create Actions with Apex REST Agent Actions](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-apex/agent-apex.md) Citations is an Agentforce feature and it requires agents to be enabled in your org. See [Set Up Your Agent](https://help.salesforce.com/s/articleView?id=ai.copilot_setup.htm) in Salesforce Help. ## Citations Basics For an agent action to include citations, the Apex action must use several citation-specific variables and types. Supported sources are unstructured data, such as knowledge articles, data from PDF files, and information from external web pages. To see citations in your agent responses, the agent must be activated. For an agent to correctly return citations, an Apex action class must include citation input and/or output classes. - `AiCopilot.GenAiCitationInput`: This enables an action to add sources to the agent reasoning context. The reasoning engine can then call the citations platform if there are valid sources referenced in the response. - `AiCopilot.GenAiCitationOutput`: This enables actions to directly provide citations for responses without calling the citations platform. **note:** For both `GenAiCitationInput` and `GenAiCitationOutput` classes, you can customize the label associated with the citation in the `label` field. Ensure that your end user has access to the URL and label for source reference content. If you want your agent action to generate text based on provided sources and determine relevant citations automatically, use `GenAiCitationInput`. If you want your agent action to generate text and citations based on predetermined logic, use `GenAiCitationOutput`. For more information on citation types, see [Citations Apex Reference](/docs/ai/agentforce/references/citations/citations-reference.html). ### Generate Citations with the Reasoning Engine The `GenAiCitationInput` class supplies the Agentforce reasoning engine with citation information. From there, the reasoning engine can determine where and how citations are added to generated content. To generate citations from a `GenAiCitationInput` Apex class, you must return the generated response as well as the citation metadata to the agent. In the example implementation, the response is generated from a prompt template and retriever. ### Generate Citations Manually The `GenAiCitationOutput` type provides direct control over how custom actions surface citations for source information. `GenAiCitationOutput` bypasses the reasoning engine’s logic and allows for explicit insertion of citations. If you have actions that you want to always return specific citations, use `GenAiCitationOutput`. Otherwise, use `GenAiCitationInput` and allow the action to call the citation platform when necessary. ## Example Citation Implementation We’ll walk through how to deploy an Apex class that uses citations to our org. This example invokes a prompt template using Connect API, parses the response, and returns a `GenAiCitationInput` object back to the Agentforce reasoning engine. As a prerequisite, ensure that you have [agents](https://help.salesforce.com/s/articleView?id=ai.agent_setup_enable.htm) and [Prompt Builder](https://help.salesforce.com/s/articleView?id=ai.prompt_builder_enable.htm) enabled in your org. **note:** For more information on how to connect your Visual Studio Code environment to Salesforce, see [Use Visual Studio Code for Salesforce Development](https://trailhead.salesforce.com/content/learn/projects/quickstart-vscode-salesforce/use-vscode-for-salesforce) on Trailhead. Copy and paste the following Apex class into your development environment. For `GenAiCitationInput`, the Apex class must return data that the Agentforce reasoning engine can use to generate a response. The prompt template and retriever are invoked, and the response from the agent contains relevant inline citations. ``` // Invokes Einstein Prompt Template via Connect API, gets response/citations, transforms citations. public class KnowledgeBaseApex { // Test method for debugging execute(). public static void test() { execute('Can you explain what is an LLM?'); } // Calls 'Knowledge_Search' Prompt Template via Connect API, gets raw response/citations. public static ConnectApi.EinsteinPromptTemplateGenerationsRepresentation execute(String query) { ConnectApi.WrappedValue inputText = new ConnectApi.WrappedValue(); inputText.value = query; Map inputParams = new Map(); // NOTE: 'Input:Question' must match the Prompt Template input variable API name. inputParams.put('Input:Question', inputText); ConnectApi.EinsteinPromptTemplateGenerationsInput executeTemplateInput = new ConnectApi.EinsteinPromptTemplateGenerationsInput(); executeTemplateInput.additionalConfig = new ConnectApi.EinsteinLlmAdditionalConfigInput(); executeTemplateInput.additionalConfig.applicationName = 'PromptBuilderPreview'; executeTemplateInput.isPreview = true; executeTemplateInput.citationMode = 'post_generation'; executeTemplateInput.inputParams = inputParams; ConnectApi.EinsteinPromptTemplateGenerationsRepresentation generationsOutput = ConnectApi.EinsteinLLM.generateMessagesForPromptTemplate( 'Knowledge_Search', // Developer Name of the Prompt Template executeTemplateInput ); return generationsOutput; } // Helper methods to transform Connect API citations to AI Copilot format. // Transforms a single Connect API source reference to AiCopilot format. public static AiCopilot.GenAiSourceReference transform(ConnectApi.EinsteinLlmGenAiSourceReference sourceRef) { List contents = new List(); for (ConnectApi.EinsteinLlmGenerationGenAiSourceContentInfo contentInfo : sourceRef.contents) { contents.add(new AiCopilot.GenAiSourceContentInfo(contentInfo.fieldName, contentInfo.objectName, contentInfo.content)); } List metadata = new List(); for (ConnectApi.EinsteinLlmGenerationGenAiSourceReferenceInfo referenceInfo : sourceRef.metadata) { metadata.add(new AiCopilot.GenAiSourceReferenceInfo(referenceInfo.link, referenceInfo.sourceObjectRecordId, referenceInfo.sourceObjectApiName)); } return new AiCopilot.GenAiSourceReference(null, contents, metadata); } // Transforms the overall Connect API citation block to AiCopilot format. public static AiCopilot.GenAiCitationInput transform(ConnectApi.EinsteinLlmGenerationCitationOutput citations) { List sourceRefs = new List(); if (citations != null && citations.sourceReferences != null) { for (ConnectApi.EinsteinLlmGenAiSourceReference source : citations.sourceReferences) { sourceRefs.add(transform(source)); } } return new AiCopilot.GenAiCitationInput(null, sourceRefs); } // Defines input (Request) and output (Response) structures for the Invocable Method. public class Request { @InvocableVariable(required=true description='Complete user question') public String Question; } public class Response { @InvocableVariable(required=true description='Generated text response from the LLM') public String Data; @InvocableVariable(required=true description='Structured citation sources') public AiCopilot.GenAiCitationInput sources; } // @InvocableMethod for Flows: gets question, calls execute, transforms citations, returns results. @InvocableMethod(label='Call Knowledge Prompt Apex' description='Invokes the Knowledge Search prompt template and returns the response with citations.') public static List executePrompt(List requests) { String question = requests[0].Question; ConnectApi.EinsteinPromptTemplateGenerationsRepresentation output = execute(question); List responses = new List(); Response response = new Response(); response.Data = output.prompt; response.sources = transform(output.citations); responses.add(response); return responses; } } ``` # Get Started with Custom Lightning Types These resources are available to help you customize your agent’s interface. | I want to... | Recommended Content | | ----------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Build using the Setup UI**

Create and configure custom Lightning types directly in Setup. | [Create a Custom Lightning Type](https://help.salesforce.com/s/articleView?id=platform.lt_intro.htm&type=5) | | **Understand the architecture**

Learn the core concepts, file structure, and how schema projection works. | [Core Concepts of Custom Lightning Types](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-core.html) | | **Choose my approach**

Decide whether to use an Apex class or define a manual JSON schema. | [Categories of Custom Lightning Types](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types.html#categories-of-custom-lightning-types) | | **Start building**

Create the definition by structuring the LightningTypeBundle metadata. | [Get Started with Lightning Types](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types.html) | | **Build with AI**

Use the Lightning Types skill in Agentforce Vibes to generate schemas and UI configurations using natural language prompts. | [Use Agentforce Vibes to Build Custom Lightning Types](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-skills.html) | | **Customize the UI**

Build `editor.json` and `renderer.json` files to override the default interface with your own Lightning web components. | [UI Configuration for Apex-Based Custom Lightning Types](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-apex.html#ui-configuration-for-apex-based-custom-lightning-types) | | **Deploy and manage**

Deploy your custom Lightning types and Lightning web components using Metadata API or Salesforce CLI. | [LightningTypeBundle Metadata Type](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-core.html#lightningtypebundle-metadata-type) | | **Integrate and test**

Assign your custom Lightning type to an agent action, and verify the behavior in Agentforce Builder. | [Integrate a Custom Lightning Type with an Agent Action](https://developer.salesforce.com/docs/ai/agentforce/guide/lightning-types-standard.md#integrate-a-custom-lightning-type-with-an-agent-action) | ## Developer Resources Use these resources to automate, deploy, and reference custom Lightning types. **Metadata API and Deployment** Use the LightningTypeBundle metadata type to define and deploy your custom Lightning types. Understand the required file structure, supported fields, and how to structure your `package.xml` manifest for deployment. - _Metadata API Developer Guide_: [LightningTypeBundles](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_lightningtypebundle.htm) **Standard Lightning Type References** Review the keywords and default behaviors for the Salesforce types. - _Lightning Types Developer Guide_: [Standard Lightning Types](https://developer.salesforce.com/docs/platform/lightning-types/references/lightning-types/lightning-types-reference.html) **Connect API** Retrieve information about the types available in your org by using Connect REST API. - _Connect REST API Developer Guide_: [Type System Resources](https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/connect_resources_type_system_resources.htm) **Lightning Types Skill** Accelerate development by using Agentforce Vibes to generate LightningTypeBundle metadata files through natural language prompts. - _Lightning Types Developer Guide_: [Use Agentforce Vibes to Build Custom Lightning Types](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-skills.html) **See Also** - [Get Started with Lightning Types](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types.html) - [Apex-Based Custom Lightning Types](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-apex.html) - [Salesforce Applications That You Can Override](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-core.html#salesforce-applications-that-you-can-override) # Get Started With Enhanced Chat v2 Enhanced Chat v2 is a new customer interface for Enhanced Web Chat on Service Cloud. Both Enhanced Chat versions allow you to connect and deploy Service agents to external chat channels. The UI of Enhanced Chat v2 can be customized with custom Lightning Types. See [Introduction to Lightning Types](https://developer.salesforce.com/docs/ai/agentforce/lightning-types/lightning-types-get-started.md). **note:** Enhanced Chat v2 is different from Enhanced Web Chat. For more information, see [What’s Enhanced Chat v2?](https://help.salesforce.com/s/articleView?id=service.enhanced_chat_v2_intro.htm&type=5). ## Context Events Enhanced Chat v2 offers a unique way to pass context events. `utilAPI` in Enhanced Web Chat now has a new `setSessionContext` method that can be used in Enhanced Chat v2 deployments. See [the enhanced chat developer guide](https://developer.salesforce.com/docs/service/messaging-web/guide/context-events.html) and [the enhanced chat reference](https://developer.salesforce.com/docs/service/messaging-web/references/m4w-reference/utilAPI.html#setsessioncontext) in Service Cloud. ## Inline Mode You can embed the Enhanced Chat v2 client directly within a specific element on your web page. Learn how to enable and configure inline mode in [Inline Mode in Enhanced Chat v2](https://developer.salesforce.com/docs/ai/agentforce/guide/enhanced-chat-inline-mode.md). ## Custom Lightning Types You can use custom lightning types to personalize the appearance of your chat deployment. To send a message on behalf of the user or pass context events from your Lightning Web Component (LWC), see [Custom Lightning Type APIs for Enhanced Chat v2](https://developer.salesforce.com/docs/service/messaging-web/guide/custom-lighting-type-apis.html). ## See Also - _Salesforce Help_: [Connect a Service Agent to Enhanced Chat v2](https://help.salesforce.com/s/articleView?id=ai.service_agent_deploy_enhanced_chat_v2.htm) # Get Started with Models and Prompts The Einstein platform provides you with powerful tools to configure and use large language models (LLMs). Quickly get started with generative AI features by using Salesforce-managed models, which are enabled by default to speed up the configuration process. The Models API allows you to access different models from your apps. Use Prompt Builder to create and manage prompt templates. To override an agent's or subagent's default model, see [Specify Different Models in Agent Script](https://developer.salesforce.com/docs/ai/agentforce/agentforce/agent-script/ascript-model.md). | Feature or API | Description | Manage Prompts | Configure Models | Use Models | Build Custom Solutions | | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | -------------- | ---------------- | ---------- | ---------------------- | | [Prompt Builder](https://developer.salesforce.com/docs/ai/agentforce/guide/prompt-builder/get-started-prompt-builder.md) | Create and manage prompt templates using Salesforce data | Yes | | | | | [AI Models](https://developer.salesforce.com/docs/ai/agentforce/guide/einstein-studio/get-started-einstein-studio.md) | Configure and test AI models | | Yes | | | | [BYOLLM](https://developer.salesforce.com/docs/ai/agentforce/guide/supported-models.md#bring-your-own-llm) | Connect external OpenAI, Azure, Vertex, or Bedrock models to AI Models | | Yes | | Yes | | [LLM Open Connector](https://github.com/salesforce/einstein-platform?tab=readme-ov-file#llm-open-connector) | Host and connect _any_ custom-built models to AI Models | | Yes | | Yes | | [Models API](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api/models-api.md) | Generate text, conversations, and embeddings via Apex and REST; access any AI Models LLM | | | Yes | Yes | ## Configure Your Models With AI Models, configure Salesforce-managed models and test prompts in a playground environment before using a model in production. You can also bring your own large language model (BYOLLM) from an LLM provider using your own account. The model is saved to the Model Library in AI Models as a foundation model that you can configure. To connect _any_ language model (including custom-built models) to the BYOLLM feature in AI Models, you can use the LLM Open Connector API specification. - [Get Started with AI Models](https://developer.salesforce.com/docs/ai/agentforce/guide/einstein-studio/get-started-einstein-studio.md) - [Salesforce-Managed Models](https://developer.salesforce.com/docs/ai/agentforce/guide/supported-models.md#salesforce-managed-models) - [Bring Your Own LLM](https://developer.salesforce.com/docs/ai/agentforce/guide/supported-models.md#bring-your-own-llm) - _Salesforce Help_: [Add a Foundation Model](https://help.salesforce.com/s/articleView?id=data.c360_a_ai_foundation_models_create.htm) - _GitHub_: [LLM Open Connector](https://github.com/salesforce/einstein-platform?tab=readme-ov-file#llm-open-connector) ## Use Models API Use the Models API to generate text, conversations, or embedding vectors. The Models API provides Apex classes and REST endpoints that connect your application to LLMs from Salesforce partners, including Anthropic, Google, and OpenAI. - [Models API Developer Guide](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api/models-api.md) - [Access Models API with Apex](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api/access-models-api-with-apex.md) - [Access Models API with REST](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api/access-models-api-with-rest.md) - [Build Lightning Web Components and Flows with Models API](https://developer.salesforce.com/docs/ai/agentforce/guide/models-api/models-api-build-lwc-flow.md) ## Design and Run Prompt Templates Simplify daily tasks by integrating prompt templates, powered by generative AI, into workflows. Create, test, revise, customize, and manage prompt templates that incorporate your CRM data from merge fields that reference record fields, flows, related lists, and Apex. Prompt Builder helps you to make effective prompts that safely connect you and your data with LLMs. - [Get Started with Prompt Builder](https://developer.salesforce.com/docs/ai/agentforce/guide/prompt-builder/get-started-prompt-builder.md) ## See Also - _Salesforce Help_: [Einstein Generative AI](https://help.salesforce.com/s/articleView?id=ai.generative_ai.htm) - _Salesforce Help_: [Agentforce and Generative AI Usage and Billing](https://help.salesforce.com/s/articleView?id=ai.generative_ai_usage.htm) # Get Started with Prompt Builder With [Prompt Builder](https://help.salesforce.com/s/articleView?id=ai.prompt_builder_intro.htm), simplify your users’ daily tasks by integrating generative AI, powered by prompt templates, into workflows. [Create](https://help.salesforce.com/s/articleView?id=ai.prompt_builder_build_template.htm) and [Manage](https://help.salesforce.com/s/articleView?id=ai.prompt_builder_manage_prompt_templates.htm) prompt templates that incorporate your CRM data from merge fields that reference record fields, flows, related lists, and Apex. Enable generative experiences on record pages or build Agentforce actions to generate summaries, descriptions, and other field values. On this page you can learn how to call a prompt template programmatically, batch process large numbers of prompt templates, and move prompt templates between orgs using metadata API. **Examples and other resources:** - _YouTube_: [Prompt Builder in Action](https://www.youtube.com/watch?v=E-6yhYx_AZk) - _Developer Blog_: [Invoke Prompt Templates from Flow, Apex, or the REST API](https://developer.salesforce.com/blogs/2024/04/invoke-prompt-templates-from-flow-apex-or-the-rest-api) ## Access Prompt Templates Programmatically ### Connect API Integrate third-party web applications with prompt templates using Connect REST API. - _Connect REST API Developer Guide_: [Prompt Template Generations Resource](https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/connect_resources_prompt_template.htm) - _Connect REST API Developer Guide_: [Prompt Template Generations Input (Request Body)](https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/connect_requests_einstein_prompt_template_generations_input.htm) - _Connect REST API Developer Guide_: [Prompt Template Generations (Response Body)](https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/connect_responses_einstein_prompt_template_generations.htm) ### Connect in Apex Use Connect in Apex to call a prompt template from Apex code. - _Apex Developer Guide_: [Resolve a Prompt Template](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/connectapi_examples_resolve_prompt_template.htm) - _Apex Reference Guide_: [EinsteinLLM Class](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_ConnectAPI_EinsteinLLM_static_methods.htm) ### Invocable Actions Use actions to call a prompt template from anywhere on the Salesforce Platform. - _Actions Developer Guide_: [Generate Prompt Response Invocable Action](https://developer.salesforce.com/docs/atlas.en-us.api_action.meta/api_action/actions_obj_generate_prompt_response.htm) ## Prompt Template Batch Processing Asynchronously generate large quantities of responses for prompt templates using Prompt Template Batch Processing in Flow or Apex. - _Apex Developer Guide_: [Prompt Template Batch Processing in Apex](https://developer.salesforce.com/docs/ai/agentforce/prompt-template-batch-job.md) - _Salesforce Help_: [Flow Core Action: Prompt Template Actions](https://help.salesforce.com/s/articleView?id=platform.flow_ref_elements_actions_generate_prompt_response.htm&type=5) ## Move Prompt Templates with Metadata API Use Metadata API to move prompt templates between sandbox and production orgs during the development process. - _Metadata API Developer Guide_: [GenAiPromptTemplate](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_genaiprompttemplate.htm) - _Metadata API Developer Guide_: [GenAiPromptTemplateActv](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_genaiprompttemplateactv.htm) ## See Also - _Trailhead_: [Prompt Builder Basics](https://trailhead.salesforce.com/content/learn/modules/prompt-builder-basics) - _Salesforce Help_: [Prompt Builder](https://help.salesforce.com/s/articleView?id=ai.prompt_builder_intro.htm) # Get Started with Testing Agents You can use several methods to test your agents. Choose the approach that best fits your workflow and technical requirements. | Feature Name | Access Method | Test Definition Format | [Custom Evaluations Support](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-custom-evaluation-criteria.md) | Description | | ---------------------------------------------------------------------------------------------- | ------------- | ---------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [**Testing Center**](https://help.salesforce.com/s/articleView?id=ai.agent_testing_center.htm) | UI | CSV | No | User interface in Salesforce org for creating and running tests. | | [**Agentforce DX**](https://developer.salesforce.com/docs/ai/agentforce/agent-dx/agent-dx-test.md) | Command Line | YAML | Yes | Salesforce CLI extension that provides agent testing capabilities. | | [**Testing API**](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-build-tests.md) | Code | XML | Yes | Direct API access using [Metadata API](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_types_list) and [Connect API](https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/intro_what_is_chatter_connect.htm). | This page provides guidance for developers using the Testing API or the Agentforce DX CLI. To learn about the Testing Center, see [Agentforce Testing Center](https://help.salesforce.com/s/articleView?id=ai.agent_testing_center.htm) in Salesforce Help. ## Prerequisites To test agents, you must have Agentforce enabled with at least one agent active. See [Set up Agents](https://help.salesforce.com/s/articleView?id=ai.copilot_setup.htm) in Salesforce Help. **important:** Agent testing is available only in sandboxes. Note that running tests consumes requests and credits and can modify data. ## Testing API Workflow This diagram shows the high-level workflow for creating, deploying, and running tests: ![API Flow](https://developer.salesforce.com/media/testing-api-workflow-steps.svg '{"class": "image-lg"}') Each step in the workflow can be completed using multiple methods: - **Create Tests**: Build tests programmatically using Metadata API or Agentforce DX. - For Metadata API, see [Build Tests in Metadata API](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-build-tests.md). - For Agentforce DX, see [Generate a Test Spec in Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/agent-dx/agent-dx-test-spec.md). - **Deploy Tests**: Deploy tests using Metadata API or Agentforce DX. - For Metadata API, see [Build Tests in Metadata API](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-build-tests.md). - For Agentforce DX, see [Create an Agent Test with Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/agent-dx/agent-dx-test-create.md). - For a walkthrough on deploying tests via the CLI (using both Testing API and Agentforce DX), see [Deploy and Run Tests in the Command Line](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-cli.md). - **Run Tests**: Execute tests using Connect API or Agentforce DX. - For Connect API, see [Run Tests in Connect API](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-connect.md). - For Agentforce DX, see [Run Agent Tests with Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/agent-dx/agent-dx-test-run.md). - For a walkthrough on running tests via the CLI (using both Testing API and Agentforce DX), see [Deploy and Run Tests in the Command Line](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-cli.md). ## See Also - [Build Tests in Metadata API](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-build-tests.md) - [Run Tests in Connect API](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-connect.md) - [Test an Agent with Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/agent-dx/agent-dx-test.md) - [Deploy and Run Tests in the Command Line](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-cli.md) - _Salesforce Help_: [Agentforce Testing Center](https://help.salesforce.com/s/articleView?id=ai.agent_testing_center.htm) # Get Started with the Agent API Bring the power of generative AI to your business with Agentforce. Build intelligent, trusted, and customizable AI agents and empower your users to get more done with Salesforce. Use the Agent API to communicate with AI agents directly from a REST API. Start sessions, send messages to the AI agent, receive messages, and end sessions using the API. **note:** Agent API isn’t supported for agents of type “Agentforce (Default)”. To access the Agent API, you must set up an external client app that supports the client credential flow. These instructions show you how to get your environment set up for use with the API and demonstrate how to make your first call to the API. ![API Flow](https://developer.salesforce.com/media/api-onboarding-steps-simpler.svg '{"class": "image-full"}') ## Prerequisites You must have Agentforce enabled with at least one agent activated. See [Set Up Your Agent](https://help.salesforce.com/s/articleView?id=ai.copilot_setup.htm) in Salesforce Help. ## Create a Salesforce App To use the Agent API, you must create an [external client app (ECA)](https://help.salesforce.com/s/articleView?id=xcloud.external_client_apps.htm). To learn how to create an ECA, see [Create an External Client App](https://help.salesforce.com/s/articleView?id=xcloud.create_a_local_external_client_app.htm) in Salesforce Help. These instructions help you create a basic app with the client credentials flow, although you can use any flow that provides a [JWT-based access token](https://help.salesforce.com/s/articleView?id=xcloud.jwt_access_tokens.htm). 1. From Setup, in the Quick Find box, enter `External Client App`, and then select **External Client Apps Manager**. 2. Select **New External Client App**. 3. Specify a name and contact email. 4. Select **Enable OAuth** and use these OAuth scopes. - **Manage user data via APIs (api)** - **Perform requests at any time (refresh_token, offline_access)** - **Access chatbot services (chatbot_api)** - **Access the Salesforce API Platform (sfap_api)** ![OAuth settings scope](https://developer.salesforce.com/media/oauth-settings-agent-api.png) 5. Select these additional OAuth settings. - **Enable Client Credentials Flow:** Allows your app to exchange its client credentials for an access token. - **Issue JWT Web Token (JWT)-based access tokens for named users:** Allows your app to issue tokens for named users. ![OAuth settings checkboxes](https://developer.salesforce.com/media/oauth-settings-2b.png) 6. Deselect: - **Require secret for Web Server Flow** - **Require secret for Refresh Token Flow** - **Require Proof Key for Code Exchange (PKCE) extension for Support Authorization Flows** 7. Create the app. 8. From your app settings, click the **Policy** tab. 9. Click **Edit**. 10. From the **OAuth Flows and External Client App Enhancements** section, check **Enable Client Credentials Flow**. 11. Set the **Run As (Username)** field to the email address of a user that has at least [API Only access](https://help.salesforce.com/s/articleView?id=platform.integration_user.htm). 12. Save the changes. ## Obtain Credentials To create a token, you need the consumer key and consumer secret from your external client app. 1. From your app settings, click the **Settings** tab. 2. Expand the **OAuth Settings** section. 3. Click the **Consumer Key and Secret** button, and copy your key and secret. You need these values to mint this token. ## Create a Token All calls to the Agent API require a token. Create a token by using the consumer key, consumer secret, and your domain name. ```bash curl https://{MY_DOMAIN_URL}/services/oauth2/token \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'client_id={CONSUMER_KEY}' \ --data-urlencode 'client_secret={CONSUMER_SECRET}' ``` - `MY_DOMAIN_URL`: You can get the domain from Setup. Search for **My Domain**. Copy the value shown in the **Current My Domain URL** field. - `CONSUMER_KEY`, `CONSUMER_SECRET`: You can get the consumer key and secret by following the instructions in [Obtain Credentials](#obtain-credentials). The previous command returns a JSON payload similar to this response. ```json { "access_token": "eyJ0bmsiOiJjb3JlL3Byb2QvM…(shortened)", "signature": "HBb7Zf4aaOUlI1V…(shortened)", "token_format": "jwt", "scope": "sfap_api chatbot_api api", "instance_url": "https://sample-org-eaa32a127e4a6b.my.salesforce.com", "id": "https://login.salesforce.com/id/00DW…Wpg5MAC/005W…nF9IAI", "token_type": "Bearer", "issued_at": "1736530186928", "api_instance_url": "https://api.salesforce.com" } ``` Copy the access token specified in the `access_token` property. This token is required when making requests to the API. ## Call the API After you set up your app and created a token, you're ready to call the API. Before making the call, gather this information. - `AGENT_ID`: The ID of the agent that you want to interact with. The method for obtaining this ID depends on which builder you used to create your agent. See [Get the Agent ID for an Agent](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-agent-id.md) for detailed instructions. - `ACCESS_TOKEN`: The token that you created in [Create a Token](#create-a-token). - `RANDOM_UUID`: A random UUID value that you provide to represent the session key. You can use this parameter to trace the conversation in your agent's event logs. - `MY_DOMAIN_URL`: From Setup, search for **My Domain**. Copy the value shown in the **Current My Domain URL** field. **important:** Be sure to use the right URLs for your org. - Use your **My Domain** URL (for example, `some_domain.my.salesforce.com`) and not simply the domain name displayed in your browser (`some_domain.lightning.force.com`). - If your org is on Government Cloud, replace `api.salesforce.com` with `api.gov.salesforce.com` in all Agent API endpoints. This curl command creates a new agent session with the Agent API. ```bash curl --location -X POST https://api.salesforce.com/einstein/ai-agent/v1/agents/{AGENT_ID}/sessions \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer {ACCESS_TOKEN}' \ --data '{ "externalSessionKey": "{RANDOM_UUID}", "instanceConfig": { "endpoint": "https://{MY_DOMAIN_URL}" }, "streamingCapabilities": { "chunkTypes": ["Text"] }, "bypassUser": true }' ``` **note:** The `bypassUser` parameter indicates whether to use the agent-assigned user instead of the logged in user. If set to `true`, the API uses the user associated with the agent. If set to `false`, the API uses the user associated with the token. For this client credentials flow scenario, we set the value to `true`. However, you may need to change this value depending on your use case. When this call succeeds, you receive a response with a session ID and additional info. Use the session ID to continue the conversation with the agent. ```json { "sessionId": "8e715939-a121-40ec-80e3-a8d1ac89da33", "_links": { "self": null, "messages": { "href": "https://api.salesforce.com/einstein/ai-agent/v1/sessions/8e715939-a121-40ec-80e3-a8d1ac89da33/messages/stream" }, "session": { "href": "https://api.salesforce.com/einstein/ai-agent/v1/agents/0XxQZ0000000Ty50AE/sessions" }, "end": { "href": "https://api.salesforce.com/einstein/ai-agent/v1/sessions/8e715939-a121-40ec-80e3-a8d1ac89da33" } }, "messages": [ { "type": "Inform", "id": "8e7cafae-0eb5-44b1-9195-21f1cd6e1f4b", "feedbackId": "", "planId": "", "isContentSafe": true, "message": "Hi, I'm an AI service assistant. How can I help you?", "result": [], "citedReferences": [] } ] } ``` Congratulations, you’ve successfully started using the Agent API! To continue using the API, see [Agent API Examples](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-examples.md) and the [Agent API Postman Collection](https://www.postman.com/salesforce-developers/salesforce-developers/collection/gwv9bjy/agent-api). ## See Also - [Get the Agent ID for an Agent](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-agent-id.md) - [Agent API Session Lifecycle](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-lifecycle.md) - [Agent API Examples](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-examples.md) - [Agent API Postman Collection](https://www.postman.com/salesforce-developers/salesforce-developers/collection/gwv9bjy/agent-api) - [Agent API Considerations](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-considerations.md) - [Agent API Troubleshooting](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-troubleshooting.md) - [Agent API Reference](/docs/ai/agentforce/references/agent-api?meta=summary) # Get the Agent ID for an Agent Before you can use the [Agent API](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.md), you need the agent ID. The method for obtaining this ID depends on which builder you used to create your agent. ## Determine Your Agent Builder Type Salesforce provides two different agent builders. To determine which one you're using: - **New Agentforce Builder**: This newer builder features a configurable interface that allows you to switch between Canvas view and Script view. It includes built-in AI assistance and Agent Script support. You access this builder through Agentforce Studio in the App Launcher. See [Explore Agentforce Builder (Beta)](https://help.salesforce.com/s/articleView?id=ai.agent_builder_intro.htm). - **Legacy Agentforce Builder**: This original builder features a visual subagent editor and dialog-based configuration. You access this builder through Setup > Agentforce Agents. See [Explore the Legacy Agentforce Builder](https://help.salesforce.com/s/articleView?id=ai.agent_builder_explore.htm). Depending on which Agentforce Builder you're using, the method for acquiring the agent ID is different. ## Get Agent ID from Legacy Agentforce Builder If you created your agent with the Legacy Agentforce Builder, you can find the agent ID directly in the URL of the Agent Overview Page. 1. From Setup, navigate to your agent. 2. When viewing the Agent Overview Page, look at the URL in your browser. 3. Copy the 18-character ID at the end of the URL. For example, using this URL, `https://mydomain.salesforce-setup.com/lightning/setup/EinsteinCopilot/0XxSB000000IPCr0AO/edit`, the agent ID is `0XxSB000000IPCr0AO`. ## Get Agent ID from New Agentforce Builder If you created your agent with the new Agentforce Builder, you need the bot ID from the [Bot](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_bot.htm) metadata type or the [BotDefinition](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_botdefinition.htm) standard object. The bot ID represents the agent ID in this case. In this example, we get the BotDefinition standard object in a [SOQL](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql.htm) query using the agent's developer name: ```sql SELECT Id, DeveloperName FROM BotDefinition WHERE DeveloperName = 'Agentforce_Service_Agent' ``` The `Id` field in the query result is your agent ID. ## See Also - Agentforce Developer Guide: [Get Started with the Agent API](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.md) - Metadata API Developer Guide: [Bot](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_bot.htm) - Standard Object Reference: [BotDefinition](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_botdefinition.htm) - Salesforce Help: [Explore Agentforce Builder (Beta)](https://help.salesforce.com/s/articleView?id=ai.agent_builder_intro.htm) - Salesforce Help: [Explore the Legacy Agentforce Builder](https://help.salesforce.com/s/articleView?id=ai.agent_builder_explore.htm) # Headless Agentforce Development Headless development means building, running, and extending software without requiring the Salesforce platform UI. In Agentforce, it means building, deploying, and operating Agentforce agents without Agentforce Builder or Setup. Author your agents from your IDE or AI coding tool, such as Claude Code. Expose the agents on any surface: web, mobile, Slack, voice, or a third-party agent host. This page covers headless development specific to Agentforce. ## What's in This Section - **[Headless Development Tools](https://developer.salesforce.com/docs/ai/agentforce/guide/headless-tools.md)**: Explore your tooling options. - **[Agentforce Vibes](https://developer.salesforce.com/docs/ai/agentforce/vs-code-extension.md)**: The AI-powered VS Code extension for Salesforce development. - **[Plugins and Skills](https://developer.salesforce.com/docs/ai/agentforce/agentforce/skills-plugins/skills-plugins.md)**: Reusable skill packages for AI coding tools. - **[MCP Solutions](https://developer.salesforce.com/docs/ai/agentforce/mcp.md)**: Salesforce's Model Context Protocol servers for AI applications. - **[Headless Agentforce Examples](https://developer.salesforce.com/docs/ai/agentforce/guide/headless-examples.md)**: End-to-end examples that build a working agent without the UI. ## See Also - [Salesforce Headless Toolkit](https://developer.salesforce.com/docs/platform/headless-get-started/guide/headless-get-started.html) - [Salesforce Headless Toolkit Developer Center](https://developer.salesforce.com/developer-centers/headless) # Headless Agentforce Examples [Agentforce Examples](https://developer.salesforce.com/docs/ai/agentforce/agentforce/agent-examples/agent-examples.md) includes headless development examples that show you how to build, deploy, and use Agentforce agents without the Salesforce UI. Look for examples in the table in End-to-End Agents with a Yes in the Headless Instructions column. The multi-surface examples show you how to complete the steps using Headless, Canvas (Salesforce UI), and sometimes Agent Script by choosing the tab for your preferred method. ## Prerequisites The headless examples have similar prerequisites. Each headless example links to these prerequisites, as needed. Let's set up your org for headless development and choose a headless development tool. ### Step 1: Set Up a Salesforce Developer Edition Org To sign up, see [Salesforce Developer Edition](https://www.salesforce.com/products/free-trial/developer/). If you’d prefer to use a different Salesforce org, verify that Einstein and Agentforce are both enabled. Your user permissions and other org settings can affect your ability to complete all the steps in the examples. **note:** Don’t run the examples on a production org because we are making changes in your org. ### Step 2: Enable Einstein and Agentforce 1. Log in to the Salesforce Developer Edition org. 2. Provision and set up Data 360, and then enable Einstein Generative AI and Agentforce. See [Set Up Einstein Generative AI and Agentforce](https://developer.salesforce.com/docs/ai/agentforce/org-setup.md). ### Step 3: Install and Authorize Salesforce CLI 1. To see if Salesforce CLI is already installed, run the `sf version` command from the command line. If it's already installed, run `sf update` to update to the latest version. 2. If Salesforce CLI isn't installed, [install it](https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli.htm). 3. To [authorize your org](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_auth.htm), run this terminal command. ```bash sf org login web --alias headless ``` 4. When the login window appears, log in to your org and click **Allow**. 5. Ensure that you have the [required permissions](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-set-up-env.html#assign-system-permissions) to publish and preview an agent in your org. 6. In your terminal, run `sf org list`. If you see the `headless` org alias in the list, you’re successfully authenticated. ### Step 4: Choose a Headless Development Tool Headless Agentforce development doesn't lock you into a single toolchain. The right choice for you depends on your preferences and the requirements for your development environment. Two common starting points are Agentforce Vibes or third-party AI coding tools, such as Claude Code, grounded with the [Salesforce skills library](https://developer.salesforce.com/docs/ai/agentforce/agentforce/skills-plugins/skills-plugins.md). For more information, see [Headless Development Tools](https://developer.salesforce.com/docs/ai/agentforce/guide/headless-tools.md). #### Claude Code Plugin (Optional) If you're using Claude Code, run this command in your terminal to install the [salesforce-development](https://claude.com/plugins/agentforce-adlc) plugin. ```bash claude plugin install salesforce-development@claude-plugins-official ``` This plugin includes a broad set of skills for Salesforce headless development. The plugin includes the `agentforce-generate`, `agentforce-test`, and `agentforce-observe` skills, which are focused on working with Agentforce agents. #### Agentforce Vibes (Optional) Agentforce Vibes is an AI-powered coding companion that helps you build and modify Salesforce apps and agents using natural language. Instead of manually writing Agent Script code or running CLI commands, you describe what you want, and Agentforce Vibes does the work. Under the hood, Agentforce Vibes uses Agentforce DX, the pro-code toolset for building agents. Agentforce Vibes comes with specialized skills for developing agents. These skills activate automatically based on your prompts. See [Get Started with Agentforce Vibes](https://developer.salesforce.com/docs/platform/agentforcevibes/guide/afv-get-started.html) in the Agentforce Vibes Developer Guide. ### Step 5: Start Building **Before we start: A note on working with your AI assistant** Throughout these headless examples, you use large language models (LLMs) to build agents in your org. Because LLMs are probabilistic, outputs can vary from run to run. If you encounter an error or an unexpected result, describe what happened to the LLM in plain language and your AI assistant will help you diagnose and fix the issue. With this conversational approach, you iterate quickly and reach a working solution. ## See Also - [Headless Agentforce Development](https://developer.salesforce.com/docs/ai/agentforce/guide/headless.md) - [Headless Development Tools](https://developer.salesforce.com/docs/ai/agentforce/guide/headless-tools.md) - [Agentforce Plugins and Skills](https://developer.salesforce.com/docs/ai/agentforce/agentforce/skills-plugins/skills-plugins.md) # Headless Development Tools Headless Agentforce development doesn't lock you into a single toolchain. Drive the entire agent lifecycle — build, deploy, test, debug — from an AI-powered IDE, a general-purpose coding agent, or Salesforce CLI. The right choice for you depends on your preferences and the requirements for your development environment. Two common starting points are Agentforce Vibes or third-party AI coding tools, such as Claude Code, grounded with the [Salesforce skills library](https://developer.salesforce.com/docs/ai/agentforce/agentforce/skills-plugins/skills-plugins.md). ## Agentforce Vibes [Agentforce Vibes](https://developer.salesforce.com/docs/ai/agentforce/vs-code-extension.md) is Salesforce's AI-powered VS Code extension. It comes prepackaged with the Salesforce skills library so that the coding agent already knows how to scaffold projects, generate Agent Script, deploy metadata, and run tests without any extra setup. The advantages include: - **Zero configuration for Salesforce work** — Skills are included so that Vibes understands Agentforce conventions from your first prompt. - **Deep platform integration** — Live preview sessions, the Agentforce DX panel, and org-aware commands are wired into the IDE. - **Up-to-date skills** — Vibes automatically updates the skills so that you get current best practices for the Agentforce development lifecycle without having to manually keep skills in sync with the latest versions. ## Third-Party AI Coding Tools Coding agents such as Claude Code, Codex, and Cursor don't ship with Salesforce context. To ground them, install the [Salesforce skills library](https://developer.salesforce.com/docs/ai/agentforce/agentforce/skills-plugins/skills-plugins.md) globally or in your project directory: ```bash npx skills add forcedotcom/sf-skills ``` After installation, skills such as `developing-agentforce`, `testing-agentforce`, and `observing-agentforce` activate automatically based on the task. The `salesforce-development` Plugin on Claude Code includes the Salesforce Skills Library. See [Agentforce Plugins and Skills](https://developer.salesforce.com/docs/ai/agentforce/agentforce/skills-plugins/skills-plugins.md). The advantages of third-party AI coding tools include: - **Work in the tool you already use** — Keep your existing coding agent and workflows instead of switching IDEs for Salesforce work. - **Composable with other skills** — Layer Salesforce skills alongside skills for your other development work in the same tool. - **Model and vendor choice** — Pick the underlying model and coding agent that fit your team, budget, and evaluation criteria. ## Lower-Level Tools To drive headless development, you can also use one of these lower-level tools: - **[Salesforce CLI](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference.htm)** — Scaffold, deploy, preview, and test agents from the terminal or a continuous integration (CI) system. - **[Agent Script](https://developer.salesforce.com/docs/ai/agentforce/agentforce/agent-script/agent-script.md)** — Author the declarative format that defines your agent's sub-agents, routing, instructions, and actions. - **[MCP Servers](https://developer.salesforce.com/docs/ai/agentforce/mcp.md)** — Use Salesforce's Model Context Protocol (MCP) solutions, such as the Salesforce DX MCP Server and Salesforce Hosted MCP Servers, to enable AI applications to securely interact with your orgs, data, and services through pre-built connections. - **[Agent API](https://developer.salesforce.com/docs/ai/agentforce/agentforce/agent-api/agent-api.md) and other Salesforce APIs** — Invoke agents and read or write platform data from any runtime. Headless development opens a world of tool possibilities. Choose your own adventure! ## See Also - [Headless Agentforce Development](https://developer.salesforce.com/docs/ai/agentforce/guide/headless.md) - [Agentforce Plugins and Skills](https://developer.salesforce.com/docs/ai/agentforce/agentforce/skills-plugins/skills-plugins.md) - [Agentforce Vibes Extension](https://developer.salesforce.com/docs/ai/agentforce/vs-code-extension.md) - [MCP Solutions for Developers](https://developer.salesforce.com/docs/ai/agentforce/mcp.md) # Headless Example: Optimize an Agent by Analyzing Production Data In this headless example, you analyze production data to identify incorrect or suboptimal agent responses and underperforming conversations. Your AI assistant identifies root causes, turns them into durable test cases, and suggests fixes, which you validate against a full test suite in your testing environment, such as a sandbox, before promoting to production. Use your preferred AI assistant, such as Claude Code or Agentforce Vibes. ## Step 1: Complete the Prerequisites Complete all the prerequisites in [Headless Examples](https://developer.salesforce.com/docs/ai/agentforce/guide/headless-examples.md). In your terminal, run `sf org list`. If you see the `headless` org alias in the list, you’re successfully authenticated. This example also requires: - Data 360 - The **Audit and Feedback** and **Agentforce Session Tracing** settings must be enabled on the Einstein Audit, Analytics, and Monitoring Setup page. You also need the Salesforce Standard Data Model managed package. See [Set Up Agent Optimization](https://help.salesforce.com/s/articleView?id=ai.generative_ai_optimize_setup.htm&type=5) in _Salesforce Help_. - An agent in production. We use the `QnA` agent created in [Ground an Agent with Agentforce Data Libraries](https://developer.salesforce.com/docs/ai/agentforce/guide/headless-examples-agent-adl.md) but the same techniques work for any agent. ## Step 2: Analyze Production Data Copy and paste this prompt into your AI assistant: ``` Analyze the last seven days of session traces for the QnA agent. This agent answers simple questions by retrieving answers from our knowledge base (RAG). Find the questions it got wrong or where it said "I don't know" or gave a low-confidence answer, at least three times each. For each one, tell me: the question customers asked, what the agent answered, what the correct answer should have been, and why it likely failed — for example, the answer wasn't in the knowledge base, the wrong article was retrieved, or the question was phrased in a way the agent didn't recognize. ``` Your AI assistant analyzes session traces to look for potential optimizations, grouped by root cause rather than as a flat list of individual suboptimal responses. If the agent doesn't have any production session traces or a test suite, your AI assistant synthesizes utterances based on the agent structure and analyzes the responses instead. Your AI assistant returns a ranked list of recurring issues and root causes, but you won't act on the suggestions yet. ## Step 3: Turn Findings into PII-Safe Test Cases Before you start to optimize the agent, convert what you learned into durable regression tests. We ensure that any Personally Identifiable Information (PII) is removed from the test cases. Copy and paste this prompt into your AI assistant: ``` For each recurring question failure you found, create a Testing Center test case in CSV format with these columns: Utterance, Expected Topic, Expected Action, Expected Outcome. Use the customer's actual question (or a close paraphrase) as the Utterance, the QnA topic as Expected Topic, the knowledge retrieval action as Expected Action, and the correct answer as the Expected Outcome. Replace any customer name, ID, or personal detail in the utterance with a generic placeholder (like "the customer" or a made-up example) so no real customer data appears in the file. Save this as a CSV file named qna-agent-test-cases.csv, formatted so it can be uploaded directly to Testing Center or submitted through the Testing Center API's test suite creation endpoint. ``` **important:** Never copy raw production records or transcripts into a test case, even temporarily. Generalize the failure condition and scrub or synthesize any supporting data first. This step keeps your test suite safe to store in source control and safe to review like code. Here's an example row in `qna-agent-eval-cases.csv`: ``` Utterance: "What's your return policy for online orders?" | Expected Topic: QnA | Expected Action: Knowledge Retrieval | Expected Outcome: "You have 30 days from the delivery date to return your product for a full refund, provided it's in original condition with all packaging, remote, and accessories." ``` This format matches what Testing Center expects for a CSV-based test suite upload, and the same fields map to the test suite creation payload if you're calling the Testing Center API directly instead of using the UI. ## Step 4: Create a Test Suite Copy and paste this prompt into your AI assistant: ``` Create a test suite and add the test cases from qna-agent-test-cases.csv. ``` **note:** Some of the initial test cases may fail because the data library files that ground the agent have gaps. The test case failures are the intended regression signal. For a production agent, you would address the test case failures by improving the quality of the grounding data for the agent. ## Step 5: Apply Fixes in a Test Environment Now that you have test cases covering the issues that you found, you can implement and validate fixes in a test environment. You don't want to make agent changes in a production environment. Depending on your preferred development lifecycle environment, you might test in a sandbox. 1. Run this terminal command to log in to your sandbox. Substitute your sandbox name for `MyDomainName--SandboxName`. ``` sf org login web --alias headless-sandbox --instance-url https://MyDomainName--SandboxName.sandbox.my.salesforce.com ``` 2. After you're authenticated in the sandbox, copy and paste this prompt into your AI assistant: ``` Apply the suggested fixes for the identified issues to a new version of the agent. Show me a diff of the proposed changes before finalizing them. ``` Review the diff before accepting the changes. Don't silently apply changes to agent metadata. It's important to keep a human in the loop! Don't publish the agent yet because we have one more quality gate to pass. ## Step 6: Validate Against the Full Test Suite (Quality Gate) Copy and paste this prompt into your AI assistant: ``` Run the full QnA agent test suite in Testing Center against the new agent version — any existing test cases plus the test cases generated from qna-agent-test-cases.csv. Report pass or fail per test case, and flag any question that now gets a wrong or low-confidence answer that previously passed. ``` Treat this step as an important quality gate, not a suggestion. Only promote the new agent version to production if the full suite passes, including any pre-existing regression test cases. A fix that resolves one issue but silently breaks another is worse than no fix at all. ## Step 7: Promote the Agent to Production After the full test suite passes, copy and paste this prompt into your AI assistant: ``` Deploy the validated agent version to production. Tag this deployment with the test suite version used to validate it. ``` ## Step 8: Monitor Your Agent for Regressions Closing the loop is what makes this process repeatable rather than a one-off optimization. Copy and paste this prompt into your AI assistant, 24–48 hours after deployment or after a meaningful volume of sessions: ``` Re-run trace analysis for this agent covering the period since the last deployment. Confirm whether the originally identified issue rate has decreased. Flag any new recurring issues introduced since the deployment. ``` If any issues persist or a new regression appears, roll back to the previous agent version and repeat the earlier steps with the updated findings. As you repeat the steps in this optimization cycle, you will build up a richer test suite and your agent response quality will continue to improve. ## See Also - [Agent Optimization](https://help.salesforce.com/s/articleView?id=ai.generative_ai_optimize.htm&type=5) # Image Components The Agentforce iOS SDK provides specialized SwiftUI components for handling image display in conversational AI interfaces. These components are designed to provide seamless image loading, caching, and display capabilities with comprehensive error handling and accessibility support. ## Component Overview The image component system consists of two main components that work together to provide comprehensive image handling: ### SalesforceAsyncImage A SwiftUI view component that provides asynchronous image loading with built-in progress indicators, error handling, and fallback support. #### Key Features - **Asynchronous Loading**: Non-blocking image loading with progress indicators - **Error Handling**: Graceful fallback for failed image loads - **Caching**: Intelligent image caching for performance optimization - **Accessibility**: Full accessibility support with proper labels and descriptions - **Customization**: Extensive theming and styling options #### Usage Patterns Use the SalesforceAsyncImage component for basic image display with built-in fallback support, or customize with your own styling and error handling. ### AgentforceImageProvider A protocol-based system that enables custom image loading and caching implementations. #### Key Features - **Custom Image Sources**: Integration with any image service or storage system - **Caching Strategies**: Flexible caching implementation for different use cases - **Error Handling**: Custom error handling and fallback mechanisms - **Performance Tuning**: Optimized image loading and processing - **Security**: Support for secure image loading with authentication #### Implementation Example Implement custom image providers that integrate with your existing image services and provide custom loading, caching, and error handling logic. ## Integration Patterns ### Basic Image Display Integrate the SalesforceAsyncImage component into your SwiftUI views for seamless image loading with built-in fallback support. ### Custom Image Provider Integration Configure custom image providers in your AgentforceConfiguration to integrate with your existing image services and caching strategies. ### Advanced Image Handling Implement advanced image handling with custom loading states, error handling, and performance optimizations for complex use cases. ## Component Benefits ### Performance - **Efficient Loading**: Optimized image loading with minimal memory usage - **Intelligent Caching**: Smart caching strategies for improved performance - **Lazy Loading**: Images are loaded only when needed - **Memory Management**: Automatic memory cleanup for large images ### User Experience - **Smooth Loading**: Seamless image loading with progress indicators - **Error Resilience**: Graceful handling of loading failures - **Accessibility**: Full accessibility support for inclusive design - **Responsive Design**: Adaptive image sizing for different screen sizes ### Developer Experience - **Easy Integration**: Simple SwiftUI integration with minimal setup - **Customizable**: Extensive customization options for different use cases - **Type Safe**: Type-safe image handling with compile-time validation - **Documentation**: Comprehensive documentation and examples ## Best Practices ### Image Optimization - **Use Appropriate Sizes**: Load images at appropriate sizes for display - **Format Selection**: Use appropriate image formats (JPEG for photos, PNG for graphics) - **Compression**: Balance quality and file size for optimal performance - **Lazy Loading**: Implement lazy loading for images outside the viewport ### Error Handling - **Provide Fallbacks**: Always provide fallback content for failed loads - **User Feedback**: Show clear error messages when images fail to load - **Retry Mechanisms**: Implement retry logic for transient failures - **Offline Support**: Handle offline scenarios gracefully ### Accessibility - **Alt Text**: Provide meaningful alternative text for images - **Screen Reader Support**: Ensure images are properly described for screen readers - **High Contrast**: Test images in high contrast mode - **Dynamic Type**: Ensure images work with iOS Dynamic Type ### Performance - **Caching**: Implement appropriate caching strategies - **Memory Management**: Monitor memory usage for large images - **Loading States**: Show loading indicators for better user experience - **Progressive Loading**: Consider progressive image loading for large images ## Next Steps - **UI Components**: See [iOS UI Components](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ui-components-ios.md) for complete component integration - **Theming**: See [iOS Theming Overview](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/theming-overview-ios.md) for image component styling - **Configuration**: See [iOS Configuration Overview](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/configuration-overview-ios.md) for image provider setup # Inline Mode in Enhanced Chat v2 Enhanced Chat v2 supports two display modes: **floating** and **inline**. - **Floating (default mode)**: Floating mode represents a chat client that appears when the user clicks the Floating Action Button (FAB) located in the bottom-right corner of the screen. - **Inline**: Inline mode renders the chat client directly within a specified target `
` element on the parent page. This mode allows the chat interface to appear seamlessly within your site’s layout. Inline mode fills the entirety of the target element. Optionally, the chat header can be toggled on or off in inline mode. **note:** Inline mode is only available for Enhanced Chat v2 deployments. For more information, see [What’s Enhanced Chat v2?](https://help.salesforce.com/s/articleView?id=service.enhanced_chat_v2_intro.htm&type=5). For detailed setup steps on Enhanced Chat APIs, see [Get Started with APIs for Enhanced Chat](https://developer.salesforce.com/docs/service/messaging-web/guide/api-overview.html). ## Enable Inline Mode 1. From Setup, in the Quick Find box, enter `Embedded Service Deployments`, and select **Embedded Service Deployments**. 2. Click **Code Snippet**. 3. Add the code snippet to your web page where you will host the chat client. 4. Update `displayMode`. Optionally, disable the chat header or prevent the chat from launching automatically: ``` embeddedservice_bootstrap.settings.displayMode = 'inline'; embeddedservice_bootstrap.settings.headerEnabled = false; // Optional embeddedservice_bootstrap.settings.disableInlineAutoLaunch = true; // Optional ``` By default, inline mode launches the chat automatically so that the target element renders content on page load. Set `disableInlineAutoLaunch` to `true` when you want the chat to open only in response to a user action, such as clicking a button on your page. Then, call the [`launchChat`](https://developer.salesforce.com/docs/service/messaging-web/guide/launch-chat.html) API from your click handler to start the chat when needed. For details, see the [`disableInlineAutoLaunch`](https://developer.salesforce.com/docs/service/messaging-web/references/m4w-reference/settingsAPI.html#disableinlineautolaunch) setting reference. 5. Specify the target element where the chat client will be embedded: ``` const myElement = document.querySelector('.chat-container'); embeddedservice_bootstrap.settings.targetElement = myElement; ``` **note:** For other Enhanced Chat snippet settings, see the [settings object](https://developer.salesforce.com/docs/service/messaging-web/references/m4w-reference/settingsAPI.html) reference. ## Configuration Troubleshooting ECv2 validates your display mode and target element configuration. You may see console warnings if inline or floating modes are not configured correctly. ### Inline Mode Without Custom Target Element If you receive a console warning that reads `displayMode is set to "inline" but targetElement is using the default (document.body). This will embed the chat into the entire page body`, you can use the example code to specify a custom container. ``` const myElement = document.querySelector('.chat-container'); embeddedservice_bootstrap.settings.targetElement = myElement; embeddedservice_bootstrap.settings.displayMode = 'inline'; ``` ### Floating Mode With Custom Target If you receive a console warning that reads `targetElement is set to a custom element but displayMode is not set to "inline". In floating mode, the chat button will float within the specified container`, there are two potential solutions. 1. Fully embed the chat by setting the mode to inline: `embeddedservice_bootstrap.settings.displayMode = 'inline';`. 2. Allow the chat to float in the default location by removing the custom `targetElement` setting. # Install the Android SDK Follow these steps to add the required dependencies to your Android project. ## Add the Maven Repository Configure your top-level `settings.gradle.kts` file as shown: ```kotlin // settings.gradle.kts dependencyResolutionManagement { repositories { google() mavenCentral() maven { url = uri("https://jitpack.io") } maven { url = uri("https://opensource.salesforce.com/AgentforceMobileSDK-Android/agentforce-sdk-repository") } maven { url = uri("https://s3.amazonaws.com/inapp.salesforce.com/public/android") } maven { url = uri("https://s3.amazonaws.com/salesforce-async-messaging-experimental/public/android") } maven { url = uri("https://opensource.salesforce.com/SharedUI-Android/shared-ui-repository") } maven { url = uri("https://opensource.salesforce.com/SLDSIcons-Android/slds-icons-repository") } } } ``` ## Add SDK Dependencies In your app-level `build.gradle.kts` file, add the dependencies for the integration path you choose. The `agentforcesdk` artifact is for the Full UI experience, while `agentforce-service` is for the Headless approach. Always pin to the latest available SDK version. Check the [Android SDK releases on GitHub](https://github.com/salesforce/AgentforceMobileSDK-Android/releases) for the current version and release notes, and replace `15.136.5` in the example below with that version. ```kotlin // build.gradle.kts plugins { id("com.android.application") id("kotlin-android") id("kotlin-kapt") id("kotlinx-serialization") id("org.jetbrains.kotlin.plugin.compose") } // app/build.gradle.kts android { compileOptions { isCoreLibraryDesugaringEnabled = true } } dependencies { // Agentforce SDK Dependencies api("com.salesforce.android.agentforcesdk:agentforce-sdk:15.136.5") // Voice support (optional) — includes Agentforce Voice native libs api("com.salesforce.android.agentforcesdk:agentforce-sdk-voice:15.136.5") coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3") } ``` After adding the dependencies, sync your project with the Gradle files. ## Next Steps - **Integration**: See [Integration Guide](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-android-integration.md) for implementation - **Requirements**: Review [Requirements](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-android-requirements.md) if you encounter issues # Install the iOS SDK To get started, install the SDK and then update some of the properties in your project. ## Install the Frameworks You can install the SDK using CocoaPods, or you can download and install the frameworks manually. ### Install with CocoaPods If you haven't already done so, install the [CocoaPods](https://cocoapods.org/about) gem, and initialize the CocoaPods main repository. ```ruby sudo gem install cocoapods pod setup ``` If you already have CocoaPods installed, update your pods to the latest version. ```ruby pod update ``` To create a Podfile, change to the root directory of your application project. Then create or edit the file named Podfile. Add the following lines to your project's Podfile. The Agentforce SDK podspec will pull in additional dependencies as needed. At the top of your `Podfile`, add the Salesforce Mobile iOS Spec Repo above the CocoaPods trunk repo. Make sure to add the CocoaPods CDN if you use any other CocoaPods dependencies. ```ruby source 'https://github.com/forcedotcom/SalesforceMobileSDK-iOS-Specs.git' source 'https://github.com/livekit/podspecs.git' source 'https://cdn.cocoapods.org/' ``` Then, in your target, add: ```ruby pod 'AgentforceSDK' pod 'Messaging-InApp-Core', '> 1.10.0' pod 'LiveKitClient' # Required to ensure CocoaPods looks in the correct source location ``` At the bottom of your podfile where you set up your post installer, configure it as shown: ```ruby post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES' end end end ``` After adding the pods, run `pod install` from your project's root directory. If CocoaPods is unable to locate the specs, try `pod install --repo-update`. ## Dependencies The AgentforceSDK includes the following key dependencies: - [AgentforceMobileService-iOS](https://github.com/forcedotcom/AgentforceMobileService-iOS): The API layer for Agentforce. - [SalesforceNetwork](https://github.com/forcedotcom/SalesforceMobileInterfaces-iOS): An interface for consuming applications to provide a networking layer to Agentforce Mobile SDK. - [SalesforceNavigation](https://github.com/forcedotcom/SalesforceMobileInterfaces-iOS): An interface for consuming applications to handle navigation events occurring within Agentforce Mobile SDK views. - [SalesforceUser](https://github.com/forcedotcom/SalesforceMobileInterfaces-iOS): A designated way to provide user information to Agentforce Mobile SDK. - [SalesforceLogging](https://github.com/forcedotcom/SalesforceMobileInterfaces-iOS): An interface for consuming applications to handle logging from within Agentforce Mobile SDK. - [Swift-Markdown-UI](https://github.com/gonzalezreal/swift-markdown-ui): A rendering library for GitHub Flavored Markdown. ## Next Steps - **Integration**: See [Integration Guide](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-ios-integration.md) for implementation - **Requirements**: Review [Requirements](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-ios-requirements.md) if you encounter issues # Install the React Native SDK Learn how to install the Agentforce Mobile SDK for React Native in your project. ## Prerequisites Before installing, ensure you meet the [system requirements](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-react-native-requirements.md). ## Install the Package Install the React Native Agentforce bridge using npm or yarn: ```bash # Using npm npm install @salesforce/react-native-agentforce # Using yarn yarn add @salesforce/react-native-agentforce ``` The package includes TypeScript types out of the box. All public exports are available from `'@salesforce/react-native-agentforce'`. ## iOS Setup Configure your iOS project to use the Agentforce SDK. ### 1. Configure the Podfile In your `ios/Podfile`, add the bridge pod. The bridge depends on `React-Core` and `AgentforceSDK` (the native iOS SDK distributed via CocoaPods). **Service Agent only (default):** ```ruby platform :ios, '17.0' target 'YourApp' do use_frameworks! :linkage => :static # React Native pods (from your standard RN template) # ... # Agentforce React Native bridge pod 'ReactNativeAgentforce', :path => '../node_modules/@salesforce/react-native-agentforce/ios' end ``` **Service Agent + Employee Agent (with Mobile SDK auth):** If you also need Employee Agent support with OAuth authentication via the Salesforce Mobile SDK, use the `WithMobileSDK` subspec: ```ruby platform :ios, '17.0' target 'YourApp' do use_frameworks! :linkage => :static # React Native pods # ... # Agentforce bridge with Mobile SDK for Employee Agent auth pod 'ReactNativeAgentforce/WithMobileSDK', :path => '../node_modules/@salesforce/react-native-agentforce/ios' end ``` The `WithMobileSDK` subspec adds a dependency on `SalesforceSDKCore`, which provides OAuth login flows. See [Employee Agent Authentication](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-react-native-employee-auth.md) for details. ### 2. Install Pods ```bash cd ios && pod install ``` ### 3. Swift Compatibility The bridge is written in Swift 5.0+. If your app is Objective-C only, Xcode prompts you to create a bridging header on first build. ### 4. Permissions (Optional) If you enable voice features (`enableVoice: true`), add the microphone usage description to your `Info.plist`: ```xml NSMicrophoneUsageDescription Used for voice input with Agentforce ``` If you enable camera/photo features (`enableMultiModalInput: true`), add: ```xml NSCameraUsageDescription Used to capture images for Agentforce NSPhotoLibraryUsageDescription Used to attach images to Agentforce conversations ``` ## Android Setup Configure your Android project to use the Agentforce SDK. ### 1. Configure build.gradle (App Level) Add the Agentforce Maven repositories and configure your app's `android/app/build.gradle`: ```gradle android { compileSdk 36 defaultConfig { minSdkVersion 29 targetSdkVersion 36 } compileOptions { sourceCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17 coreLibraryDesugaringEnabled true } buildFeatures { compose = true } } repositories { google() mavenCentral() maven { url 'https://jitpack.io' } maven { url 'https://opensource.salesforce.com/AgentforceMobileSDK-Android/agentforce-sdk-repository' } maven { url 'https://s3.amazonaws.com/inapp.salesforce.com/public/android' } maven { url 'https://s3.amazonaws.com/salesforce-async-messaging-experimental/public/android' } } dependencies { coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.1.5" // For Employee Agent with Mobile SDK auth, add: // implementation "com.salesforce.mobilesdk:SalesforceReact:13.1.1" } ``` The bridge library module includes `agentforce-sdk` as an `api` dependency. Your host app must provide `SalesforceReact` at runtime if you use Employee Agent auth. ### 2. Register the Native Package In your `MainApplication.kt` (or `.java`), register `AgentforcePackage`: ```kotlin import com.salesforce.android.reactagentforce.AgentforcePackage class MainApplication : Application(), ReactApplication { override val reactNativeHost = object : DefaultReactNativeHost(this) { override fun getPackages(): List = listOf( MainReactPackage(), AgentforcePackage(), // ... other packages ) } } ``` `AgentforcePackage` automatically registers `AgentforceModule`. It also registers `EmployeeAgentAuthBridge` if the Salesforce Mobile SDK is detected on the runtime classpath (via reflection). If the Mobile SDK is not present, Employee Agent auth is gracefully disabled. ### 3. Configure AndroidManifest.xml Register the conversation activity in your `AndroidManifest.xml`: ```xml ``` ### 4. Permissions (Optional) For camera/multi-modal input support, add to `AndroidManifest.xml`: ```xml ``` ## Verify Installation After installation, verify the native module is available: ```tsx import { AgentforceService } from "@salesforce/react-native-agentforce"; // Check if the SDK is configured (should return false initially) const configured = await AgentforceService.isConfigured(); console.log("SDK configured:", configured); ``` If you see errors about the native module not being found, see [Troubleshooting](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-react-native-troubleshooting.md). ## See Also - [Quick Start Guide](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-react-native-quick-start.md) - [Configure the SDK](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-react-native-integration.md) - [Employee Agent Authentication](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-react-native-employee-auth.md) # Integrate Agentforce SDK To use the SDK, be sure to import the Agentforce SDK packages. ```kotlin import com.salesforce.android.agentforceservice.* ``` ## Implement Core Service Interfaces The Agentforce Mobile SDK is designed for flexibility and delegates several core responsibilities to the host application. You must create concrete implementations for the following interfaces: - **AgentforceAuthCredentialProvider**: Supplies the SDK with the authentication token (e.g., OAuth 2.0 access token) required to communicate securely with Salesforce APIs. - **AgentforceInstrumentation**: A handler for the SDK to emit instrumentation and telemetry data into your app's analytics system. For authentication, create a credential provider using one of the supported authentication methods. ```kotlin class MyAppCredentialProvider : AgentforceAuthCredentialProvider { override fun getAuthCredentials(): AgentforceAuthCredentials { return AgentforceAuthCredentials.OAuth( authToken = "YOUR_AUTH_TOKEN", orgId = "YOUR_ORG_ID", userId = "YOUR_USER_ID" ) } } ``` ```kotlin class MyAppCredentialProvider : AgentforceAuthCredentialProvider { override fun getAuthCredentials(): AgentforceAuthCredentials { return AgentforceAuthCredentials.OrgJWT(orgJWT = "YOUR_ORG_JWT") } } ``` ```kotlin class MyAppCredentialProvider : AgentforceAuthCredentialProvider { override fun getAuthCredentials(): AgentforceAuthCredentials { return AgentforceAuthCredentials.Guest(url = "YOUR_GUEST_URL") } } ``` Related links: - _Salesforce Mobile SDK Developer Guide_: [OAuth 2.0 Authentication Flow](https://developer.salesforce.com/docs/platform/mobile-sdk/guide/oauth-intro-flow.html) - _Salesforce Help_: [JWT-Based Access Tokens](https://help.salesforce.com/s/articleView?id=xcloud.jwt_access_tokens.htm&type=5) ## Configure Agent In order to use the Agentforce SDK you must first identify the agent type you are targeting: Employee Agent or Service Agent. A single app may target each, but requires configuration and instantiation of separate Agentforce clients. To learn more, see [Create an Agent from a Template](https://help.salesforce.com/s/articleView?id=ai.agent_setup_type.htm) in Salesforce Help. **tip:** For guidance on gathering information for the agent configuration object, see [Agent Type Setup](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/agentforce-mobile-sdk-before-you-begin.md#agent-type) in Before You Begin. The following snippets illustrate how to configure your agent for each agent type. ```kotlin // Configure an Employee agent val configuration = AgentforceConfiguration.builder( authCredentialProvider = myAuthCredentialProvider ) .setApplication(application) .setSalesforceDomain("https://your-domain.my.salesforce.com") .setAgentId("YOUR_AGENT_ID") .setThemeManager(createCustomAgentforceThemeManager(themeMode = AgentforceThemeMode.SYSTEM)) .setNetwork(myNetworkProvider) .setLogger(myLogger) .setNavigation(myNavigation) .build() // Set mode for Employee agent val agentforceMode = AgentforceMode.FullConfig(configuration) // Create client agentforceClient?.init( authCredentialProvider = configuration.authCredentialProvider, agentforceMode = agentforceMode, application = application ) ``` ```kotlin // Configure a Service agent val agentforceMode = AgentforceMode.ServiceAgent( serviceAgentConfiguration = ServiceAgentConfiguration.builder( serviceApiURL = "https://your-service-api-url.com", organizationId = "YOUR_ORG_ID", esDeveloperName = "YOUR_CHAT_DEVELOPER_NAME" ).build() ) // Create client agentforceClient?.init( authCredentialProvider = configuration.authCredentialProvider, agentforceMode = agentforceMode, application = this.application ) ``` ```kotlin val config = AgentforceConfiguration.builder( authCredentialProvider = object : AgentforceAuthCredentialProvider { override fun getAuthCredentials(): AgentforceAuthCredentials { return AgentforceAuthCredentials.OAuth( authToken = "YOUR_AUTH_TOKEN", orgId = "YOUR_ORG_ID", userId = "YOUR_USER_ID" ) } } ).setApplication(application) .setSalesforceDomain("https://your-domain.my.salesforce.com") .setNetwork(myNetworkProvider) .setLogger(myLogger) .setNavigation(myNavigation) .setDataProvider(myDataProvider) .setFeatureFlagSettings( AgentforceFeatureFlagSettings.builder().build() ) .setCameraUriProvider(myCameraUriProvider) .setVoiceManaging(myAgentforceVoiceManaging) .setInstrumentationHandler(myAgentforceInstrumentationHandler) .setUser(myUser) .setPermission(myPermission) .setThemeManager(myAgentforceThemeManager) .setViewProvider(myAgentforceViewProvider) .build() val agentforceMode = AgentforceMode.FullConfig(config) agentforceClient?.init(authCredentialProvider = config.authCredentialProvider, agentforceMode = agentforceMode, application = application) ``` Create and retain an instance of `AgentforceClient`. It's best to hold this in a lifecycle-aware component, like a `ViewModel`, to ensure the conversation state persists across configuration changes. ## Start a Conversation Once you've initialized the `AgentforceClient`, you can start a conversation with an agent using the `startAgentforceConversation` method. ```kotlin // Start the conversation agentforceClient.startAgentforceConversation() // Get the conversation session val session = agentforceClient.fetchAgentforceSession(YOUR_AGENT_ID) ``` This method returns an `AgentforceConversation` object, which represents a single conversation with an agent. ## Next Steps - **Prebuilt UI**: See [Use Prebuilt UI](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-android-prebuilt-ui.md) for ready-to-use chat interface - **Headless**: See [Build a Headless Experience](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-android-headless.md) for custom UI implementation - **Customization**: See [Branding and Theming](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-android-branding-theming.md) for visual customization - **Custom Lightning Types**: See [Custom Lightning Types on Mobile with the Agentforce Mobile SDK](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/agent-sdk-mobile-custom-lightning-types.md) for native CLT renderers and editors # Integrate Agentforce SDK To use the SDK, be sure to import the Agentforce SDK package. ```swift import AgentforceSDK ``` ## Implement Credential Provider The Agentforce Mobile SDK has to make API calls back to your org to leverage the Agentforce Platform. In order to do so, it requires authenticated credentials, and delegates this responsibility to the app. A specific app might be using the Salesforce Mobile SDK to authenticate, or may have implemented their own OAuth client. The consuming app must implement the `AgentforceAuthCredentialProviding` protocol and provide these credentials to the SDK. **AgentforceAuthCredentialProviding**: Supplies the SDK with the authentication token required to communicate securely with Salesforce APIs. ```swift class MyAppCredentialProvider: AgentforceAuthCredentialProviding { public func getAuthCredentials() -> AgentforceAuthCredentials { return .OAuth( authToken: "YOUR_AUTH_TOKEN", orgId: "YOUR_ORG_ID", userId: "YOUR_USER_ID" ) } } ``` ```swift class MyAppCredentialProvider: AgentforceAuthCredentialProviding { public func getAuthCredentials() -> AgentforceAuthCredentials { return .OrgJWT(orgJWT: "YOUR_ORG_JWT") } } ``` ```swift class MyAppCredentialProvider: AgentforceAuthCredentialProviding { public func getAuthCredentials() -> AgentforceAuthCredentials { return .Guest("") } } ``` Related links: - _Salesforce Mobile SDK Developer Guide_: [OAuth 2.0 Authentication Flow](https://developer.salesforce.com/docs/platform/mobile-sdk/guide/oauth-intro-flow.html) - _Salesforce Help_: [JWT-Based Access Tokens](https://help.salesforce.com/s/articleView?id=xcloud.jwt_access_tokens.htm&type=5) ## Configure Agent In order to use the Agentforce SDK you must first identify the agent type you are targeting: Employee Agent or Service Agent. A single app may target each, but requires configuration and instantiation of separate Agentforce clients. To learn more, see [Create an Agent from a Template](https://help.salesforce.com/s/articleView?id=ai.agent_setup_type.htm) in Salesforce Help. **tip:** For guidance on gathering information for the agent configuration object, see [Agent Type Setup](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/agentforce-mobile-sdk-before-you-begin.md#agent-type) in Before You Begin. The following snippets illustrate how to configure your agent for each agent type. ```swift let user = User(userId: "YOUR_USER_ID", org: Org(id: "YOUR_ORG_ID"), displayName: "User's Display Name") // Configure an Employee agent let config = EmployeeAgentConfiguration( user: user, forceConfigEndpoint: "https://your-domain.my.salesforce.com" ) // Create client let client = AgentforceClient( credentialProvider: credentialProvider, mode: .employeeAgent(config) ) ``` ```swift // Set up Service UI settings let serviceUISettings = ServiceUISettings( downloadTranscript: false, // Whether to show the download transcript option endConversation: true // Whether to show the end conversation option ) // Configure a Service agent let config = ServiceAgentConfiguration( esDeveloperName: "YOUR_CHAT_DEVELOPER_NAME", organizationId: "YOUR_ORG_ID", serviceApiURL: "https://your-service-api-url.com", serviceUISettings: serviceUISettings ) // Create client let serviceClient = AgentforceClient( credentialProvider: credentialProvider, mode: .serviceAgent(config) ) ``` `AgentforceClient` must be retained for the duration of the conversation. If it's deallocated, the session will be lost. Instantiate it in an object with an appropriate lifecycle for your needs. ## Start a Conversation Once you have initialized `AgentforceClient`, you can start a conversation with an agent using the `startAgentforceConversation` method, this method is slightly different depending on whether you're targeting a Service Agent or an Employee Agent. For guidance on getting values for the `createAgentforceChatView` method, see [Agent Type Setup](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/agentforce-mobile-sdk-before-you-begin.md#agent-type). ```swift let employeeConversation = agentforceClient.startAgentforceConversation( forAgentId: "YOUR_AGENT_ID" ) ``` ```swift let serviceConversation = agentforceClient.startAgentforceConversation( forESDeveloperName: "YOUR_CHAT_DEVELOPER_NAME" ) ``` This method returns an `AgentConversation` object, which represents a single conversation with an agent. The `AgentConversation` object can be used for headless or bring your own UI experiences, and is also the central input when using one of the built-in UIs. ## Next Steps - **Prebuilt UI**: See [Use Prebuilt UI](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-ios-prebuilt-ui.md) for ready-to-use chat interface - **Headless**: See [Build a Headless Experience](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-ios-headless.md) for custom UI implementation - **Customization**: See [Theming](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-ios-branding-theming.md) for visual customization - **Custom Lightning Types**: See [Custom Lightning Types on Mobile with the Agentforce Mobile SDK](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/agent-sdk-mobile-custom-lightning-types.md) for native CLT renderers and editors # Interactive Data Science Service Errors The Interactive Data Science service is the backend infrastructure for Model Studio, where admins and data scientists create projects, connect data sources, and deploy custom models into Agentforce and Einstein AI features. Errors from this service typically indicate that a project request was invalid or referenced a resource that doesn't exist, that the org isn't enabled for the requested capability, or that a platform dependency the service relies on was temporarily unavailable. ## APPLICATION_NOT_FOUND The application identifier you supplied doesn't match a registered application visible to you. Application records are required to resolve project type, data-group affiliation, quota ceilings, and org associations, so any request that depends on an application can't proceed without one. The request wasn't processed. This error occurs when: - The identifier is incorrect or has a typo. - The application hasn't been registered for your org. - The application was deactivated. - You're calling against a different environment from the one the application is registered in. ### How to Troubleshoot To resolve this error: 1. List the applications visible to your session and confirm the identifier you're using. 2. Confirm you're calling the correct environment. 3. If the application hasn't been registered for your org, contact your Salesforce admin to register it. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `APPLICATION_NOT_FOUND` - The application identifier from the response parameters - A description of what you were trying to do when the error occurred ## AUTH_FORBIDDEN You're authenticated, but you don't have permission to perform this action. Authorization is enforced by role checks, application-membership checks, environment restrictions, and token validation. The request wasn't processed. This error occurs when: - Your user doesn't have the role required for the operation. - Your user doesn't belong to the application the operation is scoped to. - The operation is available only in non-production environments and you're calling it in production. - Your session token is missing, expired, or couldn't be parsed. ### How to Troubleshoot To resolve this error: 1. Read the response detail — it identifies whether the failure is a missing role, an application membership issue, or an authentication problem. 2. If access should be granted, contact your Salesforce admin to assign the required role or add you to the application. 3. If your token expired, refresh it through your normal authentication flow and retry. 4. If you're calling a development-only operation, switch to a non-production environment. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `AUTH_FORBIDDEN` - The required role and actual role from the response parameters - A description of what you were trying to do when the error occurred ## AUTH_TENANT_RESOLUTION_FAILED The service couldn't resolve your org's identity from the platform's authentication layer. The failure is usually temporary — retrying often succeeds. This error occurs when: - The platform's authentication layer is briefly unavailable or returning errors. - A network issue interrupted the connection between services. - The authentication layer was under heavy load when the call was made. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds and retry the same request. 2. If the error continues for more than a few minutes, the upstream service may be degraded. Check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `AUTH_TENANT_RESOLUTION_FAILED` - The approximate time window during which the failures occurred - A description of what you were trying to do when the error occurred ## AUTH_UNAUTHORIZED The service couldn't authenticate your request. The request is missing valid credentials or the credentials provided couldn't be verified. The request wasn't processed. This error occurs when: - The authentication header is missing from the request. - The token in the authentication header is malformed or couldn't be parsed. - A secondary token required by the endpoint is missing. - The token has expired. - The token signature couldn't be verified against the expected issuer. ### How to Troubleshoot To resolve this error: 1. Confirm your request includes valid authentication credentials. 2. Refresh your token through your normal authentication flow and retry. 3. If the endpoint requires additional credentials, confirm they're included. 4. If you're using an SDK, confirm it's configured for the correct environment — tokens issued for one environment don't validate in another. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `AUTH_UNAUTHORIZED` - A description of what you were trying to do when the error occurred ## AWS_ECR_FAILURE A request to the model image registry couldn't be completed. The failure is usually temporary — retrying often succeeds. This error occurs when: - The model image registry is briefly unavailable or returning errors. - A network issue interrupted the connection. - The repository or image you referenced doesn't exist. - An image policy prevented the operation. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds and retry the same request. 2. If you were listing or reading image details, confirm the repository and image tag exist. 3. If you were writing or deleting, check whether the previous attempt applied before retrying. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `AWS_ECR_FAILURE` - The operation and error code from the response parameters - A description of what you were trying to do when the error occurred ## AWS_FSX_FAILURE A request to the file storage layer couldn't be completed. The failure is usually temporary — retrying often succeeds. This error occurs when: - The file storage layer is briefly unavailable or returning errors. - A network issue interrupted the connection. - The file system or storage task you referenced is in a state that doesn't yet allow the operation (for example, still being created or updated). - A platform capacity limit was reached. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds and retry the same request. 2. If you were reading storage information, the request is safe to retry. 3. If you were modifying storage (resize, attach, detach), check the current state before retrying to avoid applying the operation twice. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `AWS_FSX_FAILURE` - The operation and error code from the response parameters - A description of what you were trying to do when the error occurred ## AWS_SAGEMAKER_FAILURE A request to the AI training infrastructure couldn't be completed. The failure is usually temporary — retrying often succeeds. This error occurs when: - The AI training infrastructure is briefly unavailable or returning errors. - A network issue interrupted the connection. - The resource you referenced is in a state that doesn't yet allow the operation (for example, still being created, updated, or deleted). - A platform capacity limit was reached. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds and retry the same request. 2. If you were reading resource status, the request is safe to retry. 3. If you were modifying a resource (deleting an endpoint, stopping a notebook), check its current state before retrying to avoid applying the operation twice. 4. If the error indicates a capacity limit was reached, contact your Salesforce admin. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `AWS_SAGEMAKER_FAILURE` - The operation and error code from the response parameters - A description of what you were trying to do when the error occurred ## BLOB_STORAGE_FAILURE A file storage operation failed while uploading, downloading, or generating a secure access link for a file. The failure is usually temporary — retrying often succeeds. This error occurs when: - The file storage service is briefly unavailable. - A network issue interrupted the transfer. - The file you referenced no longer exists or has expired. - The service received an empty response where a file record or access link was expected. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds and retry the same request. 2. If you were uploading, retry from the beginning rather than resuming a partial transfer. 3. If you were downloading, confirm the file still exists — secure access links are time-limited. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `BLOB_STORAGE_FAILURE` - The operation from the response parameters - A description of what you were trying to do when the error occurred ## CLOUD_TAG_MISSING The application's data-group affiliation is missing the required service classification tag. Without it, the service can't generate the data sources needed to create the project. The request wasn't processed. This error occurs when: - The application was registered without a data-group affiliation. - The data-group affiliation exists but doesn't include the required tag, or the tag is empty. - The application identifier points to an application configured for a different deployment. ### How to Troubleshoot To resolve this error: 1. Confirm the application identifier in the request is correct. 2. Verify the application's data-group affiliation includes the required service classification tag. Contact your Salesforce admin if you can't view or update it. 3. After the configuration is updated, resubmit the project creation request. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `CLOUD_TAG_MISSING` - The application identifier from the request - A description of what you were trying to do when the error occurred ## DATACLOUD_FAILURE A request to Data 360 couldn't be completed. The failure is usually temporary — retrying often succeeds. This error occurs when: - Data 360 is briefly unavailable or returning errors. - A network issue interrupted the connection. - A query timed out. - A query result exceeded a size limit. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds and retry the same request. 2. If the failed call was a query, narrow the scope (smaller time range or fewer rows) and retry. 3. If the failed call was a write, retry with the same data — a temporary failure doesn't partially apply changes. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DATACLOUD_FAILURE` - The operation from the response parameters - A description of what you were trying to do when the error occurred ## DATASOURCE_TENANT_MISMATCH The data source's org doesn't match the project's org configuration. A data source can only be attached to a project whose org list includes the data source's org. The request wasn't processed. This error occurs when: - A multi-org project doesn't include the data source's org in its org list. - A single-org data source is being attached to a project owned by a different org. - A data source identifier from one project is being supplied to an update on a different project. ### How to Troubleshoot To resolve this error: 1. Compare the data source org and the project org list shown in the response parameters. 2. If the data source belongs in this project, add its org to the project's org list and resubmit. 3. If the project's org list is correct, choose a data source owned by one of the project's orgs instead. 4. If you're updating a data source, confirm the identifier belongs to a data source already attached to this project. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DATASOURCE_TENANT_MISMATCH` - The data source org and project org list from the response parameters - A description of what you were trying to do when the error occurred ## DATASOURCE_TYPE_INVALID The data source type you supplied isn't allowed for this application. The response includes the value you sent and the list of allowed values. The request wasn't processed. This error occurs when: - The data source type doesn't match any allowed types for the application. - The data source entity isn't in the application's allowed entity list. - For Einstein Search data sources, the request is missing required fields or includes a configuration not permitted in production. ### How to Troubleshoot To resolve this error: 1. Read the response detail — it names the value you supplied and the list of allowed values. 2. Choose a type or entity from the allowed list and resubmit. 3. For Einstein Search data sources, confirm the request includes both an index identifier and a non-empty access policies list. In production environments, only read access is permitted. 4. If you believe the application should allow the value you sent, contact your Salesforce admin to review the application's configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DATASOURCE_TYPE_INVALID` - The supplied type and allowed types from the response parameters - A description of what you were trying to do when the error occurred ## DOWNSTREAM_TIMEOUT A platform service the request depended on didn't respond in time. The failure is usually temporary — retrying often succeeds. This error occurs when: - A downstream service is briefly slow or under heavy load. - A network slowdown interrupted the connection. - A specific operation required more time than allowed. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds and retry the same request. 2. If the operation was large or complex, try a smaller or simpler version and retry. 3. If timeouts continue across multiple attempts, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DOWNSTREAM_TIMEOUT` - A description of what you were trying to do when the error occurred ## INTERNAL_ERROR This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INTERNAL_ERROR` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## KUBERNETES_DOWNSTREAM_FAILURE A request to the platform's compute infrastructure couldn't be completed. The failure is usually temporary — retrying often succeeds. This error occurs when: - The platform's compute infrastructure is briefly unavailable or returning errors. - A network issue interrupted the connection. - A platform policy prevented the operation. - The infrastructure was rate-limiting when the call was made. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds and retry the same request. 2. If this happened while checking a resource's status, the request is safe to retry. 3. If this happened while starting, stopping, or modifying a resource, check its current state before retrying to avoid applying the operation twice. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `KUBERNETES_DOWNSTREAM_FAILURE` - A description of what you were trying to do when the error occurred ## LLM_GATEWAY_FAILURE The service couldn't get a response from the LLM gateway. The failure is usually temporary — retrying often succeeds. This error occurs when: - The LLM gateway is briefly unavailable or returning errors. - The gateway returned a malformed response. - The model you requested is overloaded or rate-limited. - Your request exceeded a gateway limit. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds and retry the same request. 2. If retries continue to fail, try a smaller request. 3. If your configuration supports multiple model options, try a different one. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `LLM_GATEWAY_FAILURE` - The operation and error code from the response parameters - A description of what you were trying to do when the error occurred ## PERSISTENCE_FAILURE The service couldn't complete a database operation. The failure is usually temporary — retrying often succeeds. This isn't a problem with your request. This error occurs when: - The database is briefly unavailable or under heavy load. - A database operation timed out. - A network issue interrupted the connection to the database. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds and retry the same request. 2. If you were reading data, the request is safe to retry. 3. If you were writing data, check the current state of the affected resource after retrying — the previous attempt may or may not have committed. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PERSISTENCE_FAILURE` - A description of what you were trying to do when the error occurred ## PROJECT_INVALID_TRANSITION The project operation you requested isn't allowed from the project's current status. The response includes the current status and the list of allowed transitions. The request wasn't processed. This error occurs when: - The project is already in the target state or past it. - The project is in an APPROVED, REVOKED, or other terminal state and you tried to update it or its data sources — only projects in UNAPPROVED status accept updates. - You tried to create an environment for a project that hasn't been approved yet. - You tried to clone a project that isn't in APPROVED status. - Another operation changed the project's status between when you read it and when you submitted this request. ### How to Troubleshoot To resolve this error: 1. Refresh the project to see its current status. 2. Review the `allowedTransitions` list in the response — it lists the valid next states from the current status. 3. Choose a transition from `allowedTransitions` and retry. If the project is in a terminal state, create a new project instead. 4. To update a project or its data sources, verify the project is in UNAPPROVED status first. 5. To clone a project, verify it's in APPROVED status first. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PROJECT_INVALID_TRANSITION` - The from-status, to-status, and allowed transitions from the response parameters - A description of what you were trying to do when the error occurred ## PROJECT_STATE_UPDATE_FAILED This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PROJECT_STATE_UPDATE_FAILED` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## PROJECT_TYPE_INVALID The combination of project type and application identifier in your request isn't allowed. The request wasn't processed. This error occurs when: - A Data Exploration application was paired with a non-`DATA_EXPLORATION` project type, or vice versa. - The application identifier is correct but it doesn't support the project type you want. - The application's supported project types were updated after the request was prepared. ### How to Troubleshoot To resolve this error: 1. Confirm the application identifier you're using. 2. If the application is a Data Exploration application, set the project type to `DATA_EXPLORATION`. If it isn't, use `PROTOTYPING` or `DEBUGGING`. 3. If you believe the application should support the type you sent, contact your Salesforce admin to review the application's configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `PROJECT_TYPE_INVALID` - The project type and application identifier from the response parameters - A description of what you were trying to do when the error occurred ## QUOTA_EXCEEDED The quota you requested for an application exceeds the ceiling configured for that application type. This is a hard limit, not a temporary rate window. Retrying with the same value won't help. The request wasn't processed. This error occurs when: - The requested quota value is greater than the ceiling for the application type. - The application type's ceiling was lowered since you last set the quota. ### How to Troubleshoot To resolve this error: 1. Compare the requested value against the ceiling — both are in the response parameters. 2. Lower the requested value to at or below the ceiling and resubmit. 3. If you need a quota above the ceiling, contact your Salesforce admin. Raising the ceiling for an application type is a policy decision that may require approvals. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `QUOTA_EXCEEDED` - The quota name, requested value, and ceiling from the response parameters - A description of what you were trying to do when the error occurred ## REGISTRY_CONFIG_INVALID This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `REGISTRY_CONFIG_INVALID` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## REQUEST_VALIDATION_FAILED The request you submitted didn't pass validation. The response includes details about the specific field, value, or rule that failed. The request wasn't processed. This error occurs when: - A required field is missing from the request, or required parameters aren't included for the operation. - An identifier in the path or body isn't a valid UUID. - A field uses a value outside the allowed set. - A resource value (CPU, GPU, or memory) is negative. - An image version is deprecated or isn't supported in your deployment environment. - The requester isn't in the project's authorized users list, or the approver is also the project creator (which isn't permitted outside development environments). ### How to Troubleshoot To resolve this error: 1. Read the response detail — it names the specific field or rule that failed and the rejected value. 2. Correct the listed field and resubmit. 3. If a project access rule failed (authorized users list, approver-equals-creator), adjust project membership or have a different user perform the action. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `REQUEST_VALIDATION_FAILED` - A redacted copy of the request you submitted - A description of what you were trying to do when the error occurred ## RESOURCE_NOT_FOUND The resource you requested doesn't exist or isn't visible to you. The request wasn't processed. This error occurs when: - The identifier in the request is incorrect or has a typo. - The resource was deleted or deactivated after you obtained the identifier. - The resource belongs to a different org or environment and isn't visible to your session. - You don't have permission to view this resource. The service returns a not-found response rather than a permission error to avoid disclosing whether the resource exists. - A platform-managed resource (such as a notebook or training job) has already completed or been cleaned up. ### How to Troubleshoot To resolve this error: 1. List the resources of the relevant type to confirm the identifier is current before using it. 2. Confirm you're calling the correct environment — identifiers don't carry over between environments. 3. If the resource was created very recently, wait a few seconds and retry. 4. If you're confident the identifier is correct and the resource should be visible to you, contact your Salesforce admin to confirm your org and permissions. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `RESOURCE_NOT_FOUND` - The resource type and identifier from the response parameters - A description of what you were trying to do when the error occurred ## SEC_IAM_FAILURE The service couldn't complete a permissions lookup because the platform's identity and access management layer was unavailable. The failure is usually temporary — retrying often succeeds. This error occurs when: - The platform's identity and access management layer is briefly unavailable or returning errors. - A network issue interrupted the connection. - A service error prevented the permission lookup from completing. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds and retry the same request. 2. If the error continues, check [trust.salesforce.com](https://trust.salesforce.com) for known incidents. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `SEC_IAM_FAILURE` - The operation from the response parameters - A description of what you were trying to do when the error occurred ## SLACK_FAILURE A notification couldn't be delivered. This is a temporary failure in the notification path — the underlying operation you performed wasn't affected. Retrying the original operation isn't necessary. This error occurs when: - The notification delivery service is briefly unavailable. - The destination channel was archived or renamed. - A network issue interrupted the delivery. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds and retry if the notification is required. 2. Confirm the destination channel is still active and configured to accept messages. 3. If the notification isn't critical, it's safe to proceed — the underlying operation completed successfully. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `SLACK_FAILURE` - A description of what you were trying to do when the error occurred ## TENANT_NOT_REGISTERED Your org hasn't been registered for the application you're calling against. Operations that depend on the org-application association can't proceed until registration is complete. The request wasn't processed. This error occurs when: - The org hasn't been registered for this application. - The org identifier in the request doesn't match the application's registered orgs. - The application's registration was removed. ### How to Troubleshoot To resolve this error: 1. Confirm the org identifier in the request is the org you intend to manage. 2. If the org isn't registered, contact your Salesforce admin to register it for this application. 3. After the org is registered, retry the request. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `TENANT_NOT_REGISTERED` - The org identifier and application identifier from the response parameters - A description of what you were trying to do when the error occurred ## TENANT_OPTED_OUT Your org has opted out of data sharing for the capability you're trying to use. This is an org-level policy controlled by your administrator. Requests that depend on this capability are blocked until the opt-out is reversed. The request wasn't processed. This error occurs when: - The org administrator has opted the org out of data sharing. - An org-wide policy refresh changed the opt-out status. - A prototyping project is being created or updated for an opted-out org — prototyping doesn't allow exceptions to the opt-out policy. ### How to Troubleshoot To resolve this error: 1. Read the response detail. If it mentions a prototyping restriction, the exception path isn't available — either use a different project type or have the org opt back in. 2. Contact your Salesforce admin to opt the org back in to data sharing. 3. After the opt-out is reversed, retry the request. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `TENANT_OPTED_OUT` - The capability and org identifier from the response parameters - A description of what you were trying to do when the error occurred ## WEBSOCKET_SESSION_FAILURE The interactive streaming session ended unexpectedly. The session can be re-established — retrying often succeeds. This error occurs when: - The underlying compute environment closed the stream. - Your authentication credentials expired during the session. - The network connection between your client and the service was interrupted. - The session exceeded an idle timeout and was closed. ### How to Troubleshoot To resolve this error: 1. Wait a few seconds, then reconnect and start a new session. 2. If your credentials expired, refresh them before reconnecting. 3. Any commands that were in progress when the session closed should be reissued in the new session. 4. If reconnects fail repeatedly, the underlying environment may not be available — try a different environment if one is configured. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `WEBSOCKET_SESSION_FAILURE` - The session state from the response parameters - A description of what you were trying to do when the error occurred # Invocable Actions for Custom Scorers After you [define a custom scorer](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-custom-scorers.md) and deploy it, a set of standard invocable actions supports the rest of the custom scorer workflow. These actions fall into two groups, based on what you're doing: - **Run scorers against agent traffic.** `triggerAgentBulkScoring` and `ingestManualAgentScores` execute your deployed scorers over a batch of sessions or intents, or record scores that a human reviewer assigned. Call these through the REST API (and, for `triggerAgentBulkScoring`, Salesforce Flow and Apex). - **Access session data inside a scorer.** `getSession` and `getLastInteraction` extract conversation data from a session so that a scorer's prompt template can evaluate the right slice of the conversation. These two actions are available _only_ as data providers inside a scorer's prompt template in Prompt Builder—you can't call them through the REST API, Flow, or Apex. Use these actions to backfill scores over historical traffic, wire scoring into a review workflow, feed a downstream reporting pipeline, or build the evaluation prompt that a custom scorer runs. ## When to Use Which Action | Use case | Action | | ---------------------------------------------------------------------------------------- | ------------------------- | | Score a batch of past sessions or intents with an LLM-driven scorer. | `triggerAgentBulkScoring` | | Record a score that a human reviewer assigned to a session or intent. | `ingestManualAgentScores` | | Pull the full conversation transcript and subagent list into a scorer's prompt template. | `getSession` | | Pull only the last interaction into a scorer's prompt template. | `getLastInteraction` | ## Prerequisites - At least one `AiAgentScorerDefinition` deployed to your org, with a version whose `status` is `Available` **and** whose `agentAssociation.isActive` is `true`. See [Scorer Status](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-custom-scorers.md#scorer-status). A scorer is only eligible to run when both conditions hold — a `Draft` version, or an `Available` version with an inactive agent association, won't produce scores. - The agent that the scorer is associated with exists in the org. - To call `ingestManualAgentScores`, the referenced scorer must have engine type `Manual`. `ingestManualAgentScores` rejects scores targeting a scorer with any other engine type. - To use `getSession` or `getLastInteraction`, your org must have Agentforce enabled with **Agentforce Session Tracing** turned on. To turn it on, from Setup enter **Einstein Generative AI** in the Quick Find box, select **Einstein Audit, Analytics, and Monitoring Setup**, and turn on **Agentforce Session Tracing**. Both actions are available only as data providers in a scorer's prompt template in Prompt Builder—you can't call them through the REST API, Flow, or Apex. ## Run Scorers Against Agent Traffic These actions operate on scorers you've already deployed. `triggerAgentBulkScoring` is a standard invocable action available through REST, Salesforce Flow, and Apex. `ingestManualAgentScores` is available through REST only. ### `triggerAgentBulkScoring` Kicks off an asynchronous pipeline that runs one or more scorers against a batch of session or intent IDs. All IDs and all scorers in a single call must belong to the same agent. ```http POST /services/data/v67.0/actions/standard/triggerAgentBulkScoring ``` #### Bulk Scoring Inputs | Field | Type | Description | | ---------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `inputIds` | `List` | Required. The session or intent IDs to score. Up to 500 per call. All IDs must belong to the same agent. | | `inputScope` | picklist | Required. The kind of ID in `inputIds`. Valid values: `Session`, `Intent`. | | `scorerApiNames` | `List` | Required. The API names of the scorers to run. Up to 10 per call. Each scorer must have a version with `status: Available` and `agentAssociation.isActive: true`, associated with the same agent as the input IDs. | | `daysBack` | integer | Optional. The number of days to look back when finding entities to score. Must be between `1` and `180`. Default is `90`. | #### Behavior - The call returns immediately; scoring runs asynchronously in the background. There is no status-polling endpoint yet — read the resulting scores from the target reporting objects once the pipeline completes. - If any input ID or scorer API name references a different agent, the entire request fails. - If a referenced scorer has no version that is both `Available` and has an active agent association, the entire request fails. #### Bulk Scoring Example: REST ```json { "inputs": [ { "inputIds": [ "0Xz01000000AbcDEAX", "0Xz01000000AbcDFAX" ], "inputScope": "Session", "scorerApiNames": [ "Customer_Drop_Off_Scorer", "Sentiment_Scorer" ] } ] } ``` #### Bulk Scoring Example: Apex ```apex Invocable.Action action = Invocable.Action.createStandardAction('triggerAgentBulkScoring'); action.setInvocationParameter('inputIds', new List{'0Xz01000000AbcDEAX', '0Xz01000000AbcDFAX'}); action.setInvocationParameter('inputScope', 'Session'); action.setInvocationParameter('scorerApiNames', new List{'Customer_Drop_Off_Scorer', 'Sentiment_Scorer'}); List results = action.invoke(); ``` You can also invoke this action from a Flow with the **Action** element by selecting **triggerAgentBulkScoring**. ### `ingestManualAgentScores` Writes reviewer-provided scores against sessions, intents, or interactions. Every score in the request must reference a scorer whose engine type is `Manual` — that is, a scorer designed to receive scores from a human reviewer rather than from an LLM. ```http POST /services/data/v67.0/actions/standard/ingestManualAgentScores ``` #### Manual Scoring Inputs | Field | Type | Description | | -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `manualScores` | string | Required. A JSON-encoded array of manual score objects. See [Manual Score Schema](#manual-score-schema). | | `sourceType` | string | Optional. A free-form string tag that identifies the source of the scores. Default is `API`. Set it to any value that helps you segment your data — for example, the name of a review UI, a batch job identifier, or the model name of an AI reviewer. | | `attribute` | string | Optional. Up to 1 KB of user-defined key-value JSON. Use this for audit metadata like a review run ID or reviewer group. The value is stored verbatim alongside each score in the same call. | | `daysBack` | integer | Optional. The number of days to look back when finding entities to score. Must be between `1` and `180`. Default is `90`. | #### Manual Score Schema Each object in the `manualScores` array has these fields. | Field | Type | Description | | ------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `scorerApiName` | string | Required. The API name of the scorer that this score belongs to. The scorer's engine type must be `Manual`; the request fails otherwise. | | `sessionId` | string | Provide exactly one of `sessionId`, `intentId`, or `interactionId`. The ID must match the input scope of the scorer. | | `intentId` | string | See `sessionId`. | | `interactionId` | string | See `sessionId`. | | `label` | string | Required. A short display label for the score, such as `Pass` or `Positive Sentiment`. | | `value` | string | Required. The score value. Up to 4 KB. Format depends on the scorer's `dataType` — for a `Number` scorer, a numeric string; for a `Text` scorer, the raw text. | | `isPassed` | boolean | Required. Whether this score maps to a `Pass` outcome. | | `associationReason` | string | Optional. Free-form reviewer notes explaining the score. Useful for audit and for training data. | #### Manual Scoring Example: REST ```json { "inputs": [ { "manualScores": "[{\"scorerApiName\":\"Customer_Drop_Off_Scorer\",\"sessionId\":\"0Xz01000000AbcDEAX\",\"label\":\"No Drop-Off\",\"value\":\"0\",\"isPassed\":true,\"associationReason\":\"Customer confirmed resolution before ending the chat.\"}]", "sourceType": "ReviewerUI", "attribute": "{\"reviewRunId\":\"run-2026-08-05-001\",\"reviewer\":\"jsmith\"}" } ] } ``` ## Access Session Data Inside a Scorer When a scorer uses a `PromptTemplate` engine, its evaluation prompt needs the conversation data it judges. `getSession` and `getLastInteraction` are standard invocable actions that return that data from a session. They're available only as data providers in a scorer's prompt template in Prompt Builder—you can't invoke them through the REST API, Flow, or Apex. Reference them inside your prompt template to feed the transcript, subagent names, agent actions, and other session details into the prompt. The two actions differ in scope: - `getSession` returns data for the **entire session** — the full transcript and every subagent that ran. - `getLastInteraction` returns data for the **last interaction only** — the final user message, the agent's response, and the subagent and agent actions from that turn. To evaluate the latest interaction inside a session-scoped scorer, use `getLastInteraction`. See [`inputScope`](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-custom-scorers.md#inputscope). Both actions take an STDM session-detail JSON string as input. For the STDM schema, see [Export Agentforce Session Tracing Data](https://developer.salesforce.com/docs/ai/agentforce/session-tracing/otel-api.md). **note:** These actions use the legacy term _topic_ in their output field names—`topicList` in `getSession` and `topicName` in `getLastInteraction`. A topic is now called a **subagent**. The field names are unchanged for API compatibility, but the values they return are the names of the subagents that ran in the session. ### `getSession` `getSession` extracts two outputs from an STDM detail view of a session: a normalized chat transcript, and the list of subagents that ran. Reference it in a scorer's prompt template when the evaluation needs the whole conversation. **Input** | Parameter | API name | Type | Description | | ------------ | ----------------- | ------ | --------------------------------------------------------------------------------- | | Session Data | `sessionDataView` | string | Required. An STDM detail-view JSON string that represents a conversation session. | **Outputs** | Parameter | API name | Type | Description | | --------------- | ---------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Chat Transcript | `chatTranscript` | string | A JSON array of message objects, each with exactly two fields: `role` (`USER`, `AGENT`, or `UNKNOWN`) and `message` (the message text). Input messages map to `USER`, output messages to `AGENT`, and anything else to `UNKNOWN`. | | Topics | `topicList` | string | A JSON array of the unique subagent names across all runs in the session, deduplicated and in the order they were reached. | **Example** For a session with two runs, `getSession` normalizes the STDM input into an ordered transcript and a list of subagents. Each message's `actorRole` becomes the transcript `role`, and each run's `topicName` feeds `topicList`. Unrecognized fields are ignored, so extra keys in the input don't cause an error. ```json { "sessionState": { "sessionId": "0LQRZ0000004Cq34AE", "startTimestamp": "2026-08-01T12:46:58.000+0000", "channel": "web" }, "actors": [ { "id": "005RZ000002WmhtYAC", "participantObject": "User", "role": "USER" }, { "id": "0XxRZ0000004Cq3", "participantObject": "Bot", "role": "AGENT", "agentApiName": "My_Service_Agent", "agentVersion": "1" } ], "metrics": { "durationMs": 20034.0, "turns": 4.0 }, "runs": [ { "runId": "run-001", "topicName": "OrderInquiry", "startTimestamp": "2026-08-01T12:46:58.000+0000", "endTimestamp": "2026-08-01T12:47:10.000+0000", "durationMs": 12034.0, "messages": [ { "message": "Hi, I need help with my order #12345.", "actorRole": "USER", "actorId": "005RZ000002WmhtYAC", "type": "Input" }, { "message": "Let me look up order #12345 right away.", "actorRole": "AGENT", "actorId": "0XxRZ0000004Cq3", "type": "Output" } ], "agentLoop": { "steps": [ { "stepId": "step-1", "type": "PLANNER", "name": "plan", "durationMs": 200.0 } ] } }, { "runId": "run-002", "topicName": "ReturnPolicy", "startTimestamp": "2026-08-01T12:47:12.000+0000", "endTimestamp": "2026-08-01T12:47:20.000+0000", "durationMs": 8000.0, "messages": [ { "message": "Can I return it if I don't like it?", "actorRole": "USER", "actorId": "005RZ000002WmhtYAC", "type": "Input" }, { "message": "You have 30 days for a full refund.", "actorRole": "AGENT", "actorId": "0XxRZ0000004Cq3", "type": "Output" } ], "agentLoop": { "steps": [ { "stepId": "step-1", "type": "PLANNER", "name": "plan", "durationMs": 180.0 } ] } } ] } ``` ```json [ { "role": "USER", "message": "Hi, I need help with my order #12345." }, { "role": "AGENT", "message": "Let me look up order #12345 right away." }, { "role": "USER", "message": "Can I return it if I don't like it?" }, { "role": "AGENT", "message": "You have 30 days for a full refund." } ] ``` ```json ["OrderInquiry", "ReturnPolicy"] ``` ### `getLastInteraction` Returns details from the last interaction in a session — the messages, the subagent and agent actions that ran, and the turn duration. `getLastInteraction` takes the same `sessionDataView` STDM JSON input as `getSession`. **Input** | Parameter | API name | Type | Description | | ------------ | ----------------- | ------ | --------------------------------------------------------------------------------- | | Session Data | `sessionDataView` | string | Required. An STDM detail-view JSON string that represents a conversation session. | **Outputs** | Parameter | API name | Type | Description | | -------------- | --------------- | ------ | --------------------------------------------------------------------------------------------------- | | User Utterance | `userUtterance` | string | The user's last message in the interaction. | | Agent Response | `agentResponse` | string | The agent's last response in the interaction. | | Topic Name | `topicName` | string | The subagent selected in the last run. The output field is named `topicName` for API compatibility. | | Action List | `actionList` | string | A JSON array of the agent action names invoked in the last run. | | Turn Duration | `turnDuration` | string | The duration of the last run, in milliseconds (for example, `1500ms`). | ### Use Session Data in a Scorer's Prompt Template A scorer with a `PromptTemplate` engine evaluates the data these actions return. Add the action to your prompt template as a data provider, then reference its outputs to build the evaluation prompt: - Use `getSession` when the scorer judges the whole conversation — for example, grade the `chatTranscript` for resolution, or check whether an expected subagent appears in `topicList`. - Use `getLastInteraction` when the scorer judges only the final turn — for example, evaluate whether `agentResponse` answers `userUtterance`, or whether `actionList` contains the agent action the turn required. ## See Also - [Create Custom Scorers for Agent Testing](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-custom-scorers.md) - [Build Tests in Metadata API](https://developer.salesforce.com/docs/ai/agentforce/guide/testing-api-build-tests.md) - [Export Agentforce Session Tracing Data](https://developer.salesforce.com/docs/ai/agentforce/session-tracing/otel-api.md) - [Metadata API Reference](/docs/ai/agentforce/references/testing-api/testing-metadata-reference.html) # iOS Analytics Overview The Agentforce iOS SDK provides comprehensive analytics and instrumentation capabilities for tracking user interactions, conversation metrics, and system performance. This system enables developers to monitor SDK usage, understand user behavior, and optimize the conversational AI experience. ## Analytics Classes - **[AgentforceInstrumentationHandler](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-instrumentation-handler-ios.md)** - Protocol for handling analytics events and integrating with analytics platforms - **[AgentforceInstrumentationEvent](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-instrumentation-event-ios.md)** - Data structure representing analytics events with context and metadata - **[AgentforceInstrumentationMarker](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-instrumentation-marker-ios.md)** - Performance markers for timing and measurement ## Analytics System Architecture The analytics system is built around a flexible event-driven architecture that supports multiple analytics platforms and custom implementations. ### Event Types - **User Interaction Events**: Track user actions, button taps, and conversation flow - **Performance Events**: Monitor response times, loading states, and system performance - **Error Events**: Capture exceptions, network failures, and error conditions - **Custom Events**: Support for application-specific analytics and business metrics ### Integration Patterns The analytics system supports various integration approaches: - **Single Platform**: Direct integration with one analytics service - **Multi-Platform**: Simultaneous integration with multiple analytics providers - **Custom Analytics**: Implementation of custom analytics logic - **Hybrid Approach**: Combination of platform analytics and custom tracking ### Event Processing Events flow through a structured pipeline: 1. **Event Generation**: SDK components generate events automatically 2. **Event Collection**: Events are collected and contextualized 3. **Event Processing**: Custom handlers process and transform events 4. **Event Delivery**: Events are sent to configured analytics platforms ## Implementation Guide ### Basic Analytics Setup Configure a basic analytics handler to process instrumentation events from the Agentforce SDK. ### Advanced Analytics Integration Implement advanced analytics handlers that can integrate with multiple analytics platforms simultaneously. ## Key Benefits - **Performance Monitoring**: Real-time insights into SDK performance - **User Behavior Analysis**: Understanding how users interact with conversational AI - **Error Tracking**: Comprehensive error reporting and debugging - **Custom Metrics**: Support for business-specific analytics requirements - **Platform Flexibility**: Integration with any analytics service ## Next Steps - **UI Components**: See [iOS UI Components](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ui-components-ios.md) for component-specific analytics - **Configuration**: See [iOS Configuration Overview](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/configuration-overview-ios.md) for analytics setup - **Integration**: See [iOS Development](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/development-ios.md) for architecture patterns # iOS Architecture & Integration Core architecture and integration components for iOS development with the Agentforce Mobile SDK. ## Available Components Implement these core protocols for integration and customization: - **[AgentConversation](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agent-conversation-ios.md)** - Core conversation interface for message handling and state management - **[AgentforceDataProviding](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-data-providing-ios.md)** - Data access abstraction for Salesforce integration ## Architecture Overview The iOS SDK follows protocol-oriented design patterns with dependency injection through provider protocols. It leverages SwiftUI for modern declarative UI development and integrates seamlessly with the SalesforceMobileSDK ecosystem. # iOS Architecture Integration Technical reference for iOS platform integration patterns and requirements. ## System Requirements | Requirement | Version | | ------------ | ------------------- | | iOS | 17.0+ | | Xcode | 16.0+ | | Swift | 5.0+ | | Dependencies | SalesforceMobileSDK | ## Core Integration Points Essential API signatures and patterns for iOS integration. ### Client Initialization ```swift AgentforceClient( credentialProvider: AgentforceAuthCredentialProviding, agentforceConfiguration: AgentforceConfiguration ) ``` ### Conversation Management ```swift client.startAgentforceConversation( forAgentId: String, sessionId: String? ) -> AgentConversation ``` ### UI Component Creation ```swift client.createAgentforceChatView( conversation: AgentConversation, delegate: AgentforceUIDelegate?, onContainerClose: () -> Void ) -> AgentforceChatView ``` ## Component Reference Complete reference of iOS components and protocols. ### UI Components | Component | Type | Description | | ----------------------------------------------------------- | ------------ | --------------------------------------- | | [AgentforceChatView](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-chat-view-ios.md) | SwiftUI View | Full conversational interface | | [AgentforceCard](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-card-ios.md) | SwiftUI View | Compact conversation summary | | [AgentforceLauncher](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-launcher-ios.md) | SwiftUI View | Floating launcher interface | | [ConversationUIContainer](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/conversation-ui-container-ios.md) | SwiftUI View | Container for embedding conversation UI | ### Core Protocols | Protocol | Purpose | | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------- | | [AgentConversation](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agent-conversation-ios.md) | Conversation interface and state management | | [AgentforceDataProviding](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-data-providing-ios.md) | Data access abstraction | | [Typography & Fonts](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/typography-and-fonts-ios.md) | Font customization; one of several theming areas alongside colors, icons, and display names | ## Related Documentation - [UI Components Implementation Guide](/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-ui-components.html) - Usage patterns and examples - [iOS Integration Guidelines](/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-ios.html) - Complete setup instructions - [Architecture Guide](/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-architecture.html) - Design patterns and concepts # iOS Authentication Overview The Agentforce iOS SDK provides a comprehensive authentication system that handles secure credential management, session persistence, and user authentication for conversational AI interactions. The system is designed to integrate seamlessly with Salesforce's authentication infrastructure while providing flexibility for custom authentication implementations. ## Authentication Architecture The authentication system is built around the `AgentforceClient` which serves as the primary entry point for all SDK functionality, including authentication management. ### Core Components - **[AgentforceClient](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-client-ios.md)** - Primary authentication coordinator and SDK entry point ## Authentication Flow The authentication system follows a secure, multi-step process: ### 1. Initial Authentication - User credentials are validated against Salesforce org - Authentication tokens are obtained and securely stored - Session state is established and maintained ### 2. Session Management - Automatic token refresh before expiration - Secure session persistence across app launches - Session validation and renewal as needed ### 3. Credential Security - Encrypted storage of authentication tokens - Secure transmission of credentials - Automatic cleanup on logout or session timeout ## Integration Patterns ### Basic Authentication Setup Configure the AgentforceClient with your credential provider to establish authenticated sessions. ### Custom Authentication Implementation Implement custom authentication providers that integrate with your existing authentication infrastructure. ## Security Features - **Token Encryption**: All authentication tokens are encrypted at rest - **Secure Transmission**: HTTPS-only communication with Salesforce services - **Session Timeout**: Automatic session expiration and cleanup - **Credential Validation**: Continuous validation of authentication state ## Authentication States The system manages several authentication states: - **Authenticated**: User is successfully authenticated and session is active - **Token Refresh**: Automatic token renewal in progress - **Unauthenticated**: User needs to re-authenticate - **Session Expired**: Session has expired and requires re-authentication ## Error Handling The authentication system provides comprehensive error handling for common scenarios: - **Invalid Credentials**: Clear error messages for authentication failures - **Network Issues**: Graceful handling of connectivity problems - **Token Expiration**: Automatic refresh attempts with fallback to re-authentication - **Session Conflicts**: Resolution of concurrent session issues ## Next Steps - **Configuration**: See [iOS Configuration Overview](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/configuration-overview-ios.md) for authentication setup - **UI Components**: See [iOS UI Components](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ui-components-ios.md) for authenticated component integration - **Integration**: See [iOS Development](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/development-ios.md) for architecture patterns # iOS Component Documentation Overview The Agentforce iOS SDK provides specialized SwiftUI components for building rich, interactive conversational AI interfaces. These components are designed to handle specific aspects of conversation UI, from image display to user input, providing a comprehensive toolkit for creating engaging chat experiences. ## Component Categories - **[Image Components](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/image-components-ios.md)** - Async image loading, display, and caching components for visual content in conversations ## Component Architecture The component system is built on SwiftUI and follows modern iOS design patterns, providing: ### Core Design Principles - **SwiftUI Native**: Built entirely with SwiftUI for optimal performance and integration - **Accessibility First**: Comprehensive accessibility support for all components - **Theme Integration**: Seamless integration with the Agentforce theming system - **Responsive Design**: Adaptive layouts that work across different screen sizes ### Component Features - **Async Loading**: Non-blocking image and content loading - **Error Handling**: Graceful fallbacks for failed content loads - **Performance Optimization**: Efficient rendering and memory management - **Customization**: Extensive theming and styling options ## Image Components The image component system provides comprehensive image handling capabilities: ### SalesforceAsyncImage A specialized async image component that provides: - **Automatic Loading**: Seamless image loading with progress indicators - **Fallback Support**: Graceful handling of loading failures - **Caching**: Intelligent image caching for performance - **Accessibility**: Full accessibility support with proper labels ### AgentforceImageProvider A protocol-based image provider system that enables: - **Custom Image Sources**: Integration with any image service - **Caching Strategies**: Flexible caching implementation - **Error Handling**: Custom error handling and fallbacks - **Performance Tuning**: Optimized image loading and processing ## Integration Patterns ### Basic Image Display Use the SalesforceAsyncImage component for seamless image loading with built-in fallback support. ### Custom Image Provider Implement custom image providers that integrate with your existing image services and caching strategies. ## Component Benefits - **Consistent UI**: Standardized components ensure consistent user experience - **Performance**: Optimized for smooth scrolling and fast loading - **Accessibility**: Built-in accessibility features for inclusive design - **Theming**: Seamless integration with Agentforce theme system - **Error Resilience**: Robust error handling and fallback mechanisms ## Best Practices - **Use Async Components**: Leverage async loading for better performance - **Implement Fallbacks**: Always provide fallback content for failed loads - **Test Accessibility**: Verify accessibility features work with screen readers - **Optimize Images**: Use appropriate image sizes and formats - **Handle Errors**: Implement comprehensive error handling for network issues ## Next Steps - **UI Components**: See [iOS UI Components](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ui-components-ios.md) for complete component integration - **Theming**: See [iOS Theming Overview](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/theming-overview-ios.md) for component styling - **Integration**: See [iOS Development](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/development-ios.md) for architecture patterns # iOS Configuration Overview The Agentforce iOS SDK provides a comprehensive configuration system that enables fine-grained control over agent behavior, UI customization, and system integration. The configuration system is built around the central `AgentforceConfiguration` class, which serves as the primary configuration hub for all SDK functionality. ## Configuration Architecture The configuration system follows a hierarchical structure with clear separation of concerns: ### Core Configuration Classes - **[AgentforceConfiguration](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-configuration-ios.md)** - Central configuration hub with all SDK settings and dependencies - **[EmployeeAgentConfiguration](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/employee-agent-configuration-ios.md)** - Employee-specific agent behavior and settings - **[ServiceAgentConfiguration](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/service-agent-configuration-ios.md)** - Service agent configuration for customer interactions - **[AgentforceFeatureFlagSettings](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-feature-flag-settings-ios.md)** - Feature flag management for A/B testing and gradual rollouts - **[AgentforcePageContext](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-page-context-ios.md)** - Page context information for contextual agent behavior - **[AgentforcePageContextProviding](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-page-context-providing-ios.md)** - Protocol for providing page context data ## Configuration Categories ### Agent Configuration The SDK supports two primary agent types with specialized configuration: #### Employee Agent Configuration - **Internal Use Cases**: Employee assistance and productivity tools - **Access Control**: Role-based access and permissions - **Integration**: Deep integration with Salesforce org data - **Customization**: Employee-specific UI and behavior preferences #### Service Agent Configuration - **Customer Interactions**: External customer support and service - **Brand Consistency**: Customer-facing branding and messaging - **Escalation Handling**: Service agent escalation workflows - **Compliance**: Customer data protection and privacy controls ### System Configuration #### Core Dependencies - **Data Provider**: Custom data access and Salesforce integration - **Image Provider**: Image loading and caching strategies - **Analytics Handler**: Analytics and instrumentation integration - **Theme Manager**: Visual theming and customization #### Network and Navigation - **Salesforce Network**: HTTP communication and network abstraction - **Navigation Handler**: App navigation integration - **Logging Provider**: Diagnostic and debugging information #### Feature Management - **Feature Flags**: Dynamic feature toggling and experimentation - **Debug Settings**: Development and debugging capabilities - **Performance Tuning**: System optimization and resource management ## Configuration Patterns ### Minimal Configuration Start with essential configuration parameters for basic SDK functionality. ### Full-Featured Configuration Implement comprehensive configuration with all available options for production deployments. ## Configuration Benefits - **Flexibility**: Comprehensive customization options for any use case - **Modularity**: Independent configuration of different system components - **Extensibility**: Easy integration of custom providers and handlers - **Maintainability**: Clear separation of concerns and configuration management - **Testing**: Support for different configurations for development and testing ## Best Practices - **Start Simple**: Begin with minimal configuration and add complexity as needed - **Use Feature Flags**: Leverage feature flags for gradual rollouts and A/B testing - **Custom Providers**: Implement custom providers for specialized requirements - **Environment Separation**: Use different configurations for development, staging, and production - **Documentation**: Document custom configurations and their purposes ## Next Steps - **Authentication**: See [iOS Authentication Overview](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/authentication-overview-ios.md) for credential setup - **UI Components**: See [iOS UI Components](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ui-components-ios.md) for interface building - **Integration**: See [iOS Development](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/development-ios.md) for architecture patterns # iOS Data Models Overview The Agentforce iOS SDK provides a comprehensive data modeling system that handles all aspects of conversational AI data, from Salesforce object metadata to participant interactions. The data models are designed to provide type-safe, efficient access to conversation data while maintaining compatibility with Salesforce's data structures. ## Data Model Architecture The data modeling system is organized into several key categories that work together to provide a complete data representation layer: ### Core Data Models - **[AgentforceObjectRepresentation](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-object-representation-ios.md)** - Salesforce object metadata including labels, fields, and theme information - **[AgentforceRecordRepresentation](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-record-representation-ios.md)** - Individual record data with field values and relationships - **[AgentforceUIApiRecord](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-ui-api-record-ios.md)** - UI-optimized record handling for display components - **[AgentforceUIApiRecordCollection](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-ui-api-record-collection-ios.md)** - Collection management for multiple records - **[AgentforceUIApiFields](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-ui-api-fields-ios.md)** - Comprehensive field definitions with metadata and validation rules - **[AgentforceUIApiFieldValues](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-ui-api-field-values-ios.md)** - Field value handling with type safety and formatting - **[AgentforceUIApiObjectInfo](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-ui-api-object-info-ios.md)** - Complete object information including relationships and capabilities - **[AgentforceUIApiRecordTypeInfo](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-ui-api-record-type-info-ios.md)** - Record type metadata for specialized record handling ### Interaction Models - **[ParticipantAction](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/participant-action-ios.md)** - Individual participant actions and behaviors - **[ParticipantInteraction](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/participant-interaction-ios.md)** - Participant interaction patterns and sequences - **[EscalationAction](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/escalation-action-ios.md)** - Escalation workflow actions and triggers ## Data Model Categories ### Object and Record Management The SDK provides comprehensive support for Salesforce data structures: #### Object Representation - **Metadata Management**: Complete object metadata including labels, descriptions, and capabilities - **Field Definitions**: Detailed field information with types, validation rules, and display properties - **Relationship Mapping**: Object relationships and reference handling - **Theme Integration**: Visual theming information for object display #### Record Handling - **Data Access**: Efficient access to record data with type safety - **Field Values**: Comprehensive field value management with proper typing - **Collection Support**: Bulk record operations and collection management - **UI Optimization**: Record data optimized for display in UI components ### Interaction Tracking The system provides detailed tracking of conversation interactions: #### Participant Management - **Action Tracking**: Monitor individual participant actions and behaviors - **Interaction Patterns**: Analyze interaction sequences and patterns - **Status Management**: Track participant status and availability - **Role Management**: Handle different participant roles and permissions #### Escalation Handling - **Escalation Triggers**: Automatic and manual escalation triggers - **Workflow Management**: Escalation workflow state and progression - **Agent Handoff**: Seamless handoff between different agent types - **Status Tracking**: Monitor escalation status and resolution ## Data Model Benefits ### Type Safety - **Compile-Time Validation**: Type-safe access to all data structures - **Null Safety**: Proper handling of optional values and null states - **Type Inference**: Automatic type inference for improved developer experience ### Performance - **Efficient Access**: Optimized data access patterns for UI components - **Memory Management**: Efficient memory usage for large data sets - **Caching**: Intelligent caching of frequently accessed data ### Integration - **Salesforce Compatibility**: Full compatibility with Salesforce data structures - **API Integration**: Seamless integration with Salesforce APIs - **Custom Extensions**: Support for custom data extensions and modifications ## Usage Patterns ### Basic Object Access Access object metadata and field information using the comprehensive data model classes. ### Record Operations Work with record collections and individual record data using the optimized data models. ### Interaction Tracking Track participant actions and interactions using the specialized interaction models. ## Best Practices - **Use Type-Safe Access**: Leverage the type-safe data models for reliable data access - **Handle Optional Values**: Properly handle optional values and null states - **Optimize for UI**: Use UI-optimized models for display components - **Cache Frequently Used Data**: Implement caching for performance-critical data - **Monitor Performance**: Track data access patterns and optimize as needed ## Next Steps - **UI Components**: See [iOS UI Components](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ui-components-ios.md) for data model integration - **Configuration**: See [iOS Configuration Overview](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/configuration-overview-ios.md) for data provider setup - **Integration**: See [iOS Development](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/development-ios.md) for architecture patterns # iOS Error Handling Overview The Agentforce iOS SDK provides a comprehensive error handling system that manages errors, exceptions, and failure scenarios throughout the conversational AI experience. The system is designed to provide clear error information, graceful degradation, and recovery mechanisms to ensure a robust user experience. ## Error Handling Architecture The error handling system is built around a hierarchical error classification system that provides clear error context and recovery guidance: ### Core Error Classes - **[AgentforceSDKError](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-sdk-error-ios.md)** - Core SDK error definitions with specific error types and context - **[AgentforceDataProviderErrors](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-data-provider-errors-ios.md)** - Data access and processing error handling ## Error Classification System The SDK categorizes errors into distinct types for targeted handling and recovery: ### SDK Core Errors The `AgentforceSDKError` enum provides specific error types for core SDK functionality: - **`defaultAgentNotConfigured`**: The default agent for the organization has not been configured - **`featureDisabled`**: Requested feature is disabled via feature flags - **`invalidConversation`**: The provided conversation instance is invalid or corrupted - **`missingSessionOrViewModel`**: Required session or view model components are missing - **`noActiveSession`**: No active conversation session available for operations - **`transcriptGenerationFailed`**: Server-side transcript generation failed - **`unableToStartASession`**: Failed to establish a session with the Agentforce service ### Data Provider Errors Data access and processing errors that occur during: - **Data Retrieval**: Failed data fetching from Salesforce - **Data Processing**: Errors during data transformation and validation - **Data Storage**: Issues with local data persistence - **Data Synchronization**: Problems with data sync between local and remote ### System Errors - **Network Errors**: Connectivity issues, timeouts, and communication failures - **Authentication Errors**: Credential validation and session management issues - **Configuration Errors**: Invalid configuration settings and missing dependencies - **Resource Errors**: Memory, storage, and system resource limitations ## Error Handling Strategies ### Error Recovery The SDK implements multiple recovery strategies: #### Automatic Recovery - **Retry Mechanisms**: Automatic retry for transient network errors - **Fallback Strategies**: Alternative approaches when primary methods fail - **State Restoration**: Recovery from corrupted or invalid states - **Resource Management**: Automatic cleanup and resource reallocation #### User-Guided Recovery - **Clear Error Messages**: User-friendly error descriptions and guidance - **Recovery Actions**: Suggested actions for error resolution - **Context Preservation**: Maintaining conversation context during recovery - **Graceful Degradation**: Reduced functionality when full recovery isn't possible ### Error Reporting The system provides comprehensive error reporting capabilities: #### Error Logging - **Structured Logging**: Consistent error logging format and context - **Error Categorization**: Automatic error classification and tagging - **Context Preservation**: Rich context information for debugging - **Performance Impact**: Minimal performance impact from error logging #### Analytics Integration - **Error Tracking**: Integration with analytics systems for error monitoring - **Trend Analysis**: Error pattern analysis and reporting - **User Impact Assessment**: Understanding error impact on user experience - **Proactive Monitoring**: Early detection of error patterns and issues ## Implementation Patterns ### Basic Error Handling Implement comprehensive error handling for SDK operations using the specific error types and recovery mechanisms. ### Advanced Error Handling Create custom error handlers that provide specialized error processing and recovery strategies for different error categories. ## Error Handling Benefits - **Robust User Experience**: Graceful handling of errors prevents app crashes - **Clear Error Communication**: Users understand what went wrong and how to fix it - **Developer Debugging**: Rich error information for debugging and troubleshooting - **System Reliability**: Automatic recovery mechanisms maintain system stability - **Performance Monitoring**: Error tracking helps identify and resolve performance issues ## Best Practices - **Handle Errors Gracefully**: Always implement proper error handling for SDK operations - **Provide User Feedback**: Show clear, actionable error messages to users - **Implement Recovery**: Provide recovery mechanisms where possible - **Log Errors Appropriately**: Use structured logging for debugging and monitoring - **Test Error Scenarios**: Include error handling in your testing strategy ## Next Steps - **UI Components**: See [iOS UI Components](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ui-components-ios.md) for error display components - **Configuration**: See [iOS Configuration Overview](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/configuration-overview-ios.md) for error handling setup - **Integration**: See [iOS Development](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/development-ios.md) for architecture patterns # iOS Integration Guide This section gives integration guidelines for building an iOS app with the Agentforce Mobile SDK. For the quick start experience, see [iOS Quick Start](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-ios-quick-start.md). # iOS Quick Start Guide Get up and running quickly with the Agentforce Mobile SDK for iOS using these instructions. ## Before You Begin Ensure you have: - A Salesforce org with Agentforce enabled - An agent configured in your org (Employee Agent or Service Agent) - The required values from your Salesforce org depending on agent type For detailed setup instructions, see [Before You Begin](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/agentforce-mobile-sdk-before-you-begin.md). ### For Service Agent You need these values from your Salesforce org: - **Service API URL**: Setup > Embedded Service Deployments > your deployment > Settings - **Organization ID**: Setup > Company Information - **ES Developer Name**: Setup > Embedded Service Deployments > Developer Name ### For Employee Agent You need these values from your Salesforce org: - **Agent ID**: From the Agent Details page URL (the 18-character ID at the end) - **User ID**: From the user profile. See [Find the Salesforce ID for a User](https://help.salesforce.com/s/articleView?id=000381643&type=1). - **My Domain URL**: Setup > My Domain > Current My Domain URL ## 1. Install Dependencies Add the Agentforce SDK to your project using CocoaPods. ```ruby # Add to the top of your podfile source 'https://github.com/forcedotcom/SalesforceMobileSDK-iOS-Specs.git' source 'https://github.com/livekit/podspecs.git' source 'https://cdn.cocoapods.org/' # Add to your target target 'MyApp' do pod 'AgentforceSDK' pod 'Messaging-InApp-Core', '> 1.10.0' pod 'LiveKitClient' # Required to ensure Cocoapods looks in the correct source location end # Add to the bottom of your podfile where you set up your post installer post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES' end end end ``` To learn more, see [Install the iOS SDK](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-ios-install.md). ## 2. Add Required Permissions See [iOS Requirements](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-ios-requirements.md). ## 3. Implement Credential Provider To use the SDK, be sure to import the Agentforce SDK package. ```swift import AgentforceSDK ``` Create a credential provider using one of the supported authentication methods. ```swift class MyAppCredentialProvider: AgentforceAuthCredentialProviding { public func getAuthCredentials() -> AgentforceAuthCredentials { return .OAuth( authToken: "YOUR_AUTH_TOKEN", orgId: "YOUR_ORG_ID", userId: "YOUR_USER_ID" ) } } ``` ```swift class MyAppCredentialProvider: AgentforceAuthCredentialProviding { public func getAuthCredentials() -> AgentforceAuthCredentials { return .OrgJWT(orgJWT: "YOUR_ORG_JWT") } } ``` ```swift class MyAppCredentialProvider: AgentforceAuthCredentialProviding { public func getAuthCredentials() -> AgentforceAuthCredentials { return .Guest("") } } ``` To learn more, see [Integrate Agentforce SDK](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-ios-integration.md). ## 4. Configure Chat Configure your chat object for Employee agent or Service agent. **tip:** For guidance on gathering information for the agent configuration object, see [Agent Type Setup](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/agentforce-mobile-sdk-before-you-begin.md#agent-type) in Before You Begin. ```swift let user = User(userId: "YOUR_USER_ID", org: Org(id: "YOUR_ORG_ID"), displayName: "User Display Name") // Configure an Employee agent let config = EmployeeAgentConfiguration( user: user, forceConfigEndpoint: "https://your-domain.my.salesforce.com" ) // Create client let client = AgentforceClient( credentialProvider: credentialProvider, mode: .employeeAgent(config) ) ``` ```swift // Set up Service UI settings let serviceUISettings = ServiceUISettings( downloadTranscript: false, // Whether to show the download transcript option endConversation: true // Whether to show the end conversation option ) // Configure a Service agent let config = ServiceAgentConfiguration( esDeveloperName: "YOUR_CHAT_DEVELOPER_NAME", organizationId: "YOUR_ORG_ID", serviceApiURL: "https://your-service-api-url.com", serviceUISettings: serviceUISettings ) // Create client let serviceClient = AgentforceClient( credentialProvider: credentialProvider, mode: .serviceAgent(config) ) ``` To learn more, see [Integrate Agentforce SDK](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-ios-integration.md). ## 5. Start and Present Chat Start the chat conversation and present the chat UI. ```swift let employeeConversation = agentforceClient.startAgentforceConversation( forAgentId: "YOUR_AGENT_ID" ) let chatView = try client.createAgentforceChatView( conversation: employeeConversation, delegate: nil, onContainerClose: { /* handle close */ } ) ``` ```swift let serviceConversation = agentforceClient.startAgentforceConversation( forESDeveloperName: "YOUR_CHAT_DEVELOPER_NAME" ) let chatView = try client.createAgentforceChatView( conversation: serviceConversation, delegate: nil, onContainerClose: { /* handle close */ } ) ``` To learn more, see [Integrate Agentforce SDK](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-ios-integration.md). For guidance on getting values for the `createAgentforceChatView` method, see [Agent Type Setup](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/agentforce-mobile-sdk-before-you-begin.md#agent-type). ## Next Steps - **Customization**: See [Theming](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-ios-branding-theming.md) for visual customization - **Full Integration**: See [Integration Guide](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/guide/agentforce-mobile-sdk-ios-integration-overview.md) for complete implementation # iOS Theming Overview The Agentforce iOS SDK provides a comprehensive theming system that enables complete visual customization of the conversational AI interface. The theming system is built around a flexible, protocol-based architecture that supports dynamic theming, system integration, and custom brand implementations. ## Theming Architecture The theming system is built on a protocol-based architecture that provides maximum flexibility and customization: ### Core Theming Classes - **[AgentforceThemeManager](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-theme-manager-ios.md)** - Primary theme management interface combining theming capabilities with state observation - **[AgentforceDefaultThemeManager](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-default-theme-manager-ios.md)** - Default implementation with standard Salesforce theming - **[AgentforceThemeMode](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-theme-mode-ios.md)** - Theme mode configuration for light, dark, and system modes - **[AgentforceColorToken](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-colors-ios.md)** - Type-safe enum of every color token, generic and per-component - **[Color Token Reference](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-color-token-reference-ios.md)** - Every color token in the palette, with its default light and dark value ## Color System Architecture The color system is built around semantic color tokens that provide consistent theming across all components: ### Color Categories #### Surface Colors - **`surface1`** / **`surface2`**: Primary view background colors - **`surfaceContainer1`** / **`surfaceContainer2`** / **`surfaceContainer3`**: Component container backgrounds - **`disabledContainer1`** / **`disabledContainer2`**: Disabled component backgrounds #### Text Colors - **`onSurface1`** / **`onSurface2`** / **`onSurface3`**: Text colors for different emphasis levels - **`onDisabled1`** / **`onDisabled2`**: Text colors for disabled states #### Accent Colors - **`accent1`** / **`accent2`** / **`accent3`**: Interactive element colors - **`accentContainer1`**: Branded component container backgrounds - **`onAccent1`**: Text colors for accent containers #### Feedback Colors - **`error1`** / **`errorContainer1`** / **`onError1`**: Error state colors - **`successContainer1`** / **`onSuccess1`**: Success state colors - **`warningContainer1`** / **`onWarning1`**: Warning state colors - **`info1`** / **`infoContainer1`**: Information state colors #### Border Colors - **`border1`** / **`border2`**: Decorative and functional border colors - **`borderSuccess1`**: State-specific border color #### Generic Foundation Colors - **`brandBase50`** / **`brandBase70`** / **`brandBase90`**: Cosmos foundation colors A number of generic tokens — including `errorBase50`, `feedbackWarning1`, `feedbackWarningContainer1`, `borderDisabled1`, `borderError1`, `borderInverse2`, and the three Generic Foundation Colors above — are declared by the shared design system but aren't currently read by any Agentforce view, so overriding them has no visible effect today. See the [Color Token Reference](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-color-token-reference-ios.md#generic-tokens) for the full list. ## Theme Mode System The SDK supports multiple theme modes for different use cases: ### Light Mode - **Optimized for**: Light backgrounds and bright environments - **Color Contrast**: High contrast for readability - **Brand Integration**: Consistent with light-themed applications ### Dark Mode - **Optimized for**: Dark backgrounds and low-light environments - **Eye Comfort**: Reduced eye strain in dark environments - **Modern Aesthetics**: Contemporary dark theme design ### System Mode - **Automatic Adaptation**: Follows iOS system appearance preferences - **User Preference**: Respects user's system-wide theme choice - **Dynamic Switching**: Real-time theme changes based on system settings ## Implementation Patterns ### Basic Theme Setup Configure the default theme manager with your preferred theme mode for immediate theming support. ### Custom Theme Implementation Implement custom theme managers that provide brand-specific colors and theming capabilities. ### Dynamic Theme Switching Create theme controllers that enable real-time theme switching between light, dark, and system modes. ## Advanced Theming Features ### Reactive Updates - **Observable State**: Real-time theme updates across all components - **Automatic Propagation**: Theme changes automatically update all UI elements - **Performance Optimized**: Efficient theme change handling without performance impact ### System Integration - **iOS Appearance**: Full integration with iOS appearance system - **Dynamic Type**: Integration with iOS Dynamic Type for text scaling ### Full Visual Customization - **Colors**: Override generic or component-level color tokens - **Icons**: Replace any of the 23 customizable icon slots, with optional light and dark variants - **Consistent Theming**: Unified theming across all SDK components ## Theming Benefits - **Brand Consistency**: Maintain consistent branding across all conversational AI interfaces - **User Experience**: Provide familiar and comfortable visual experiences - **Accessibility**: Support for accessibility requirements and preferences - **Flexibility**: Easy customization for different use cases and requirements - **Performance**: Optimized theming system with minimal performance impact ## Best Practices - **Use Semantic Colors**: Leverage semantic color tokens for consistent theming - **Test All Modes**: Verify theming across light, dark, and system modes - **Accessibility**: Ensure proper contrast ratios and accessibility compliance - **Brand Integration**: Maintain brand consistency while respecting user preferences - **Performance**: Use efficient theme switching to avoid UI lag ## Next Steps - **UI Components**: See [iOS UI Components](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/ui-components-ios.md) for component theming - **Configuration**: See [AgentforceConfiguration](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-configuration-ios.md) for theme setup - **Integration**: See [iOS Development](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/development-ios.md) for architecture patterns # iOS UI Components Native SwiftUI components for building conversational interfaces with the Agentforce Mobile SDK. ## Available Components Build conversational interfaces with these native SwiftUI components: - **[AgentforceChatView](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-chat-view-ios.md)** - Full-screen conversational interface with message history and input handling - **[AgentforceCard](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-card-ios.md)** - Compact conversation summary card with quick action capabilities - **[AgentforceLauncher](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/agentforce-launcher-ios.md)** - Floating action button for easy conversation access - **[ConversationUIContainer](https://developer.salesforce.com/docs/ai/agentforce-mobile-sdk/references/agentforce-mobile-sdk/conversation-ui-container-ios.md)** - Container view for embedding conversation UI ## Integration All UI components integrate seamlessly with the Agentforce theming system and support custom styling through the `AgentforceTheming` enum. # Knowledge Library Example In this example, we create a knowledge library and learn how to work with data categories. To complete this example, you must first get an access token and set up shell variables, as described in [Get Started with ADL API](https://developer.salesforce.com/docs/ai/agentforce/guide/adl-get-started.md). ## Step 1: Create a Knowledge Library This step creates a new knowledge library. You must specify the Knowledge object fields to index. The `primaryIndexField1` and `primaryIndexField2` fields are required and can't be changed after creation. All specified fields must exist on the Knowledge object (KnowledgeKAV) and be text-based types (STRING or TEXTAREA). ```shell RESPONSE_ADL=$(curl -s -X POST "$ORG_URL/services/data/v66.0/einstein/data-libraries" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "masterLabel": "'"${ADL_Name}"'", "developerName": "'"${ADL_DevName}"'", "groundingSource": { "sourceType": "KNOWLEDGE", "knowledgeConfig": { "primaryIndexField1": "Title", "primaryIndexField2": "Summary", "contentFields": ["UrlName"] } } }') echo "$RESPONSE_ADL" | jq '.' LIBRARY_ID=$(echo "$RESPONSE_ADL" | jq -r '.libraryId') echo "LIBRARY_ID: $LIBRARY_ID" ``` The curl command calls the `einstein/data-libraries` resource. For more information, see [ADL Resource Reference](https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/connect_resources_adl.htm) in the Connect REST API Developer Guide. **Expected Response:** JSON with `libraryId` and `groundingSource` fields. ### Create a Library with Data Categories To scope the library to specific data categories, set `isDataCategoryRuleEnabled` to `true` and provide either category IDs or category names. You can't provide both in the same request. Data categories enable you to restrict what the knowledge library is allowed to search, ensuring strict governance. **Using category names** (format: `groupDeveloperName.categoryDeveloperName`): ```shell RESPONSE_ADL=$(curl -s -X POST "$ORG_URL/services/data/v66.0/einstein/data-libraries" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "masterLabel": "'"${ADL_Name}"'", "developerName": "'"${ADL_DevName}"'", "groundingSource": { "sourceType": "KNOWLEDGE", "knowledgeConfig": { "primaryIndexField1": "Title", "primaryIndexField2": "Summary", "contentFields": ["UrlName"], "isDataCategoryRuleEnabled": true, "dataCategorySelectionNames": ["Products.Hardware", "Products.Software"] } } }') echo "$RESPONSE_ADL" | jq '.' LIBRARY_ID=$(echo "$RESPONSE_ADL" | jq -r '.libraryId') echo "LIBRARY_ID: $LIBRARY_ID" ``` **Using category IDs:** ```shell RESPONSE_ADL=$(curl -s -X POST "$ORG_URL/services/data/v66.0/einstein/data-libraries" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "masterLabel": "'"${ADL_Name}"'", "developerName": "'"${ADL_DevName}"'", "groundingSource": { "sourceType": "KNOWLEDGE", "knowledgeConfig": { "primaryIndexField1": "Title", "primaryIndexField2": "Summary", "contentFields": ["UrlName"], "isDataCategoryRuleEnabled": true, "dataCategorySelectionIds": ["ka01234567890ABCAA", "ka01234567890ABCBB"] } } }') echo "$RESPONSE_ADL" | jq '.' LIBRARY_ID=$(echo "$RESPONSE_ADL" | jq -r '.libraryId') echo "LIBRARY_ID: $LIBRARY_ID" ``` Category names are converted to IDs at creation time. Duplicate entries are silently de-duplicated. ## Step 2: Trigger Indexing Index the Knowledge articles in the library. ```shell curl -s -X POST "$ORG_URL/services/data/v66.0/einstein/data-libraries/$LIBRARY_ID/indexing" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ | jq '.' ``` **Expected Response:** includes `{ "status": "IN_PROGRESS" }`. ## Step 3: Poll Until Ready This command loops every 10 seconds until the status is READY or FAILED. ```shell while true; do STATUS_RESPONSE=$(curl -s "$ORG_URL/services/data/v66.0/einstein/data-libraries/$LIBRARY_ID/status" \ -H "Authorization: Bearer $ACCESS_TOKEN") STATUS=$(echo "$STATUS_RESPONSE" | jq -r '.indexingStatus.status') ALL_STAGES_SUCCESS=$(echo "$STATUS_RESPONSE" | jq -r ' [.indexingStatus.stages[]?.status] | all(. == "SUCCESS") and length > 0') echo "Status: $STATUS | All stages SUCCESS: $ALL_STAGES_SUCCESS" if [ "$STATUS" = "READY" ] || [ "$STATUS" = "FAILED" ] || [ "$ALL_STAGES_SUCCESS" = "true" ]; then echo "$STATUS_RESPONSE" | jq '.' break fi sleep 10 done ``` **Expected Response:** After a few minutes, the status transitions to `READY`. This script exits when the status is READY, FAILED, or all stages report SUCCESS. The READY status requires chunking/embedding to complete for the SearchIndex. `ALL_STAGES_SUCCESS` means that the ADL pipeline is done even if SearchIndex processing is still pending. ## Step 4: Update the Knowledge Library After the library reaches a READY status, you can update `contentFields` and data category configuration. The `primaryIndexField1` and `primaryIndexField2` fields are immutable after creation. You can't update a library while indexing is in progress. ```shell curl -s -X PATCH "$ORG_URL/services/data/v66.0/einstein/data-libraries/$LIBRARY_ID" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "groundingSource": { "knowledgeConfig": { "contentFields": ["UrlName", "Answer__c"], "isDataCategoryRuleEnabled": true, "dataCategorySelectionNames": ["Products.Hardware", "Support.Installation"] } } }' | jq '.' ``` **Expected Response:** Updated library details with the new configuration. ## Step 5: Get Library Details ```shell curl -s "$ORG_URL/services/data/v66.0/einstein/data-libraries/$LIBRARY_ID" \ -H "Authorization: Bearer $ACCESS_TOKEN" | jq '.' ``` **Expected Response:** Library details including configuration and status. ```json { "dataSpaceScopeId": "9gTxx0000000001EAA", "description": "Verify primary fields maintain insertion order", "developerName": "knowledge_adl_testing_char_limit_issue_3", "groundingSource": { "groundingSourceType": "KNOWLEDGE", "knowledgeConfig": { "contentFields": ["Summary"], "dataCategorySelectionIds": [], "isDataCategoryRuleEnabled": false, "isRestrictToPublicArticle": false, "primaryIndexField1": "UrlName", "primaryIndexField2": "Title" } }, "libraryId": "1JDxx0000004CfoGAE", "masterLabel": "Primary Field Order Test1", "retrieverId": "1Cxxx0000004CAeCAM", "retrieverLabel": "KA_knowledge_adl_testing_char_limit", "sourceType": "KNOWLEDGE", "status": "IN_PROGRESS" } ``` ## Step 6: Get Library Status ```shell curl -s "$ORG_URL/services/data/v66.0/einstein/data-libraries/$LIBRARY_ID/status" \ -H "Authorization: Bearer $ACCESS_TOKEN" | jq '.' ``` **Expected Response:** Status of the library assets. ```json { "indexingStatus": { "lastUpdatedAt": 1781028766720, "libraryId": "1JDxx0000004CfoGAE", "stages": { "DATA_LAKE_OBJECT": { "completedAt": 1780945980000, "status": "SUCCESS" }, "DATA_MODEL_OBJECT": { "completedAt": 1780945980000, "status": "SUCCESS" }, "SEARCH_INDEX": { "completedAt": 1780945980000, "status": "SUCCESS" }, "DATA_STREAM": { "completedAt": 1780945979000, "status": "SUCCESS" }, "RETRIEVER": { "completedAt": 1780945980000, "status": "SUCCESS" } }, "status": "IN_PROGRESS" } } ``` ## Step 7: Delete the Library ```shell curl -s -X DELETE "$ORG_URL/services/data/v66.0/einstein/data-libraries/$LIBRARY_ID" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -w "\nHTTP Status: %{http_code}\n" ``` **Expected Response:** `HTTP Status: 204`. A library can't be deleted if it's referenced by active resources such as agents. # Kotoba Voices This page lists the Kotoba voice personas and the locales each one supports. Kotoba provides the default voice for Japanese (`ja`): if you don't set a `persona_id` for a Japanese agent, it uses the voice marked **(default)** here. Set a `persona_id` only when you want a specific voice. For how to select a model and configure a voice, see [Configure Voice Models in Agent Script](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice.md). ## Japanese - ja | Voice | Gender | Voice ID | Description | | :---- | :----- | :------- | :---------- | | Azawa (default) | Male | `e5d63b40f254` | Natural male voice with a composed and conversational Japanese delivery. | | Me | Female | `43aa916c0e61` | Natural female voice with a warm and approachable Japanese delivery. | ## Related Topics - [Voice Catalog for Agentforce Voice](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice-catalog.md) - [Configure Voice Models in Agent Script](https://developer.salesforce.com/docs/ai/agentforce/guide/ascript-voice.md) # Language Detection Service Errors The language detection service identifies the language of text submitted through Agentforce and Einstein AI features. Errors from this service typically indicate that the input text was too short or the wrong type, that required parameters were missing, or that the pipeline configuration connecting language detection to other steps was incorrect. ## DEPENDENCY_RESULT_NOT_FOUND Language detection couldn't complete because a required internal step didn't produce the expected result. This is a platform-internal condition and isn't caused by your Agentforce configuration. The request wasn't processed. This error occurs when: - An internal platform condition prevented the language detection service from completing the request. ### How to Troubleshoot If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `DEPENDENCY_RESULT_NOT_FOUND` - The approximate time the error occurred ## INPUT_TEXT_BELOW_MINIMUM The text sent to the language detection step is too short for the service to identify a language reliably. The service needs at least the minimum number of characters shown in the error message to produce a confident result. The request wasn't processed. This error occurs when: - The upstream step or variable that feeds the language detection step produced text shorter than the minimum length. - Whitespace or punctuation was trimmed and the remaining content fell below the minimum. - The language detection step is receiving an empty or near-empty value from its input mapping. ### How to Troubleshoot To resolve this error: 1. In Agentforce Builder, open the subagent or agent action that runs the language detection step. 2. Trace the input variable that feeds the step's text field and confirm it produces text of at least the required length. 3. If short inputs are expected in your flow, add a length check earlier and route them around the language detection step. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `INPUT_TEXT_BELOW_MINIMUM` - The name of the subagent or agent action that contains the language detection step ## LDS_INTERNAL_ERROR This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `LDS_INTERNAL_ERROR` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## LDS_LINGUA_PROCESSING_ERROR The language detection service couldn't complete the analysis. The request format was valid, but a temporary internal issue prevented the service from producing a result. The same input often succeeds on a second attempt. This error occurs when: - A temporary issue arose inside the language detection engine while processing the input. - Temporary resource pressure affected the service. ### How to Troubleshoot To resolve this error: 1. Wait a moment and try again. This issue is usually temporary. 2. If the error persists across multiple attempts, note the trace ID and contact Salesforce Customer Support. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `LDS_LINGUA_PROCESSING_ERROR` - Whether the error repeated across multiple attempts ## MULTIPLE_DEPENDENCY_RESULTS Language detection couldn't complete because an internal step produced an unexpected result. This is a platform-internal condition and isn't caused by your Agentforce configuration. The request wasn't processed. This error occurs when: - An internal platform condition prevented the language detection service from completing the request. ### How to Troubleshoot If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `MULTIPLE_DEPENDENCY_RESULTS` - The approximate time the error occurred ## NO_DEPENDENCIES_FOUND Language detection couldn't complete because an internal step in the service didn't produce output. This is a platform-internal condition and isn't caused by your Agentforce configuration. The request wasn't processed. This error occurs when: - An internal platform condition prevented the language detection service from completing the request. ### How to Troubleshoot If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `NO_DEPENDENCIES_FOUND` - The approximate time the error occurred ## POSTPROCESSOR_INTERNAL_ERROR This error code indicates an unexpected system error and not an issue with your configuration. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `POSTPROCESSOR_INTERNAL_ERROR` - Any context that might help with the investigation, such as when the error occurred, what you or your end user were doing at the time, and whether you're able to reproduce it ## REQUIRED_PARAMS_MISSING The language detection step ran without the input text it needs. The service requires text to analyze, and it couldn't find a text input from the step's configuration or from an upstream step in the flow. The request wasn't processed. This error occurs when: - The language detection step's text input isn't mapped to a variable or upstream output. - The variable mapped to the text input resolves to an empty or missing value at runtime. - An upstream step expected to supply the text either didn't run or produced no output. ### How to Troubleshoot To resolve this error: 1. In Agentforce Builder, open the language detection step's configuration. 2. Confirm the text input is mapped to a variable or the output of an upstream step. 3. If the text comes from an upstream step, verify that step runs before the language detection step and produces a value. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `REQUIRED_PARAMS_MISSING` - The name of the subagent or agent action that contains the language detection step ## TEXT_MUST_BE_STRING The language detection step received a value that isn't text. Language detection only works with text data, so the request couldn't be processed. This is typically caused by an upstream step or integration producing the wrong data type. The request wasn't processed. This error occurs when: - An upstream step or integration produced a non-text value where text was expected. ### How to Troubleshoot To resolve this error: 1. Note the trace ID and the time the error occurred. 2. Contact Salesforce Customer Support to investigate the source of the non-text input. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `TEXT_MUST_BE_STRING` - The approximate time the error occurred - The name of the subagent or agent action that contains the language detection step ## THRESHOLD_OUT_OF_RANGE The confidence threshold configured on the language detection step is outside the allowed range. The threshold controls how confident the service must be before returning a language match. Valid values are between `0` and `1` inclusive. The request wasn't processed. This error occurs when: - The confidence threshold field on the language detection step is set to a negative number or a value greater than `1`. - A percentage value (for example, `50`) was entered instead of a decimal (for example, `0.5`). - A variable used to set the confidence threshold at runtime resolves to a value outside the `[0, 1]` range. ### How to Troubleshoot To resolve this error: 1. In Agentforce Builder, open the language detection step's configuration. 2. Set the confidence threshold to a decimal value between `0` and `1` (for example, `0.5`, not `50`). 3. If the confidence threshold is set from a variable, confirm the variable's source produces values in the `[0, 1]` range. If the issue persists, contact Salesforce Customer Support with the following information. - The trace ID from the error response (`instance` field, format `urn:trace:...`) - The error code: `THRESHOLD_OUT_OF_RANGE` - The confidence threshold value that was configured # Lightning Types in Agent Action Agent actions use standard Lightning types to define the structure, validate, and display of data in Salesforce when an action is triggered. Here’s how Lightning types are used in the context of agent actions. - **Mapping Data Types to Lightning Types** In Salesforce, Apex classes are often used to handle business logic, such as processing inputs and returning results. For example, consider an agent action called Flight Booking that searches for available flights. When you trigger this agent action, the inputs and outputs from the Apex class are mapped to standard Lightning types. So if an Apex class accepts inputs like dates, strings, and numbers, these data types are mapped to the corresponding standard Lightning types, such as lightning\_\_dateType, lightning\_\_stringType, and lightning\_\_numberType. This mapping ensures that the data is structured correctly. - **Schema Definition and Validation** Each standard Lightning type has an associated schema that defines the structure of the data and the rules for its validation, such as maximum length and format. This schema ensures that the data that you enter to the action conforms to the expected type and format, which helps to avoid errors during execution. For example, if an action expects you to enter Date data, the schema ensures that you enter only a valid date. - **Automatic UI Generation** When you trigger an action, Salesforce automatically generates the appropriate UI components for the action’s inputs and outputs based on the mapped Lightning types. The UI displays relevant input fields, pickers, or tables according to the standard Lightning type. For example: - If an Apex action expects a multiline text input, a multiline text field appears in the UI, based on the standard Lightning type lightning\_\_multilineTextType. - For date fields, a date picker automatically appears in the UI, based on the standard Lightning type lightning\_\_dateType. - **Rendering the Data** The renderer component associated with each Lightning type displays the data when an action is executed. For example: - For an Apex class that returns a list of flights, you can use the standard Lightning type lightning\_\_listType to display the flight data in an appropriate format. This rendering ensures that the output is displayed in a structured and readable way, whether it’s a list, table, or simple text. - **Out-of-the-Box Components** When you use standard Lightning types, Salesforce provides ready-to-use components for input and output with minimal configuration required. These components handle most use cases, offering a seamless experience when working with standard Lightning types in agent actions. ## Example: Standard Lightning Types in Agent Action Here’s how agent actions output is displayed by using standard Lightning types. **Agent Action: Summarize Record** This image shows the input and output settings for the 'Summarize Record' agent action, which uses standard Lightning types. ![Input and output settings for the 'Summarize Record' agent action, with standard Lightning types used in the Data Type field for both configurations.](https://developer.salesforce.com/media/lightning-types-images/Summerize-Record.png '{"class": "image-framed"}') Here’s how a record summary appears in the action output. ![A summary of an account shows company details, opportunities, open cases, activities, contacts, and recent purchases.](https://developer.salesforce.com/media/lightning-types-images/Summerize-Record-Output.png '{"class": "image-md image-framed"}') The agent action output has these elements. 1. Utterance 2. Agent Response 3. Agentforce Component (LWC) 4. Agentforce Action Output/Input Type (Lightning Type) **Agent Action: Identify Objects By Name** This image shows the input and output settings for the 'Identify Object By Name' agent action, which uses standard Lightning types. ![Input and output settings for the 'Identify Objects By Name' agent action, with standard Lightning types used in the Data Type field for both configurations.](https://developer.salesforce.com/media/lightning-types-images/Identify-Object.png '{"class": "image-framed"}') Here's how the list of accounts appears in the action output. ![A list displays account names and phone numbers.](https://developer.salesforce.com/media/lightning-types-images/Identify-Object-Output.png '{"class": "image-md image-framed"}') The agent action output has these elements. 1. Utterance 2. Agent Response 3. Agentforce Component (LWC) 4. Agentforce Action Output/Input Type (Lightning Type) ## Integrate a Custom Lightning Type with an Agent Action To apply your custom user interface, connect your custom Lightning type to the agent action’s parameters. 1. Open the agent action that you want to edit. 2. Configure the rendering for the appropriate agent action input or output. - For the action’s input, edit the **Input Rendering** parameter and select your custom Lightning type. - For the action’s output, edit the **Output Rendering** parameter and select your custom Lightning type. 3. Save the agent action. # Limits on Apex REST APIs API Catalog limits apply to the use of Apex REST APIs in agents. See [View Apex APIs in API Catalog](https://help.salesforce.com/s/articleView?id=platform.api_catalog_view_apex_apis.htm&type=5). If you reach the limit for the number of active operations or objects, inactivate or delete unneeded operations in the APIs in the API Catalog. Before inactivating or deleting an Apex REST API catalog registration, remove it from any agent action that's using it. # Limits on AuraEnabled Apex Classes in Agents API Catalog limits apply to the use of AuraEnabled Apex classes in agents. See [View Apex APIs in API Catalog](https://help.salesforce.com/s/articleView?id=platform.api_catalog_bring_apex_apis_into.htm&type=5). If you reach the limit for the number of active operations or objects, inactivate or delete unneeded operations in the APIs in the API Catalog. Before inactivating or deleting an AuraEnabled API catalog registration, remove it from any agent action that's using it. # Manage Agent Script Agents You can configure, deploy, and test your agents from your Salesforce org, or at the command line with [Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/agent-dx/agent-dx.md). ## Configure and Deploy Agents To configure or deploy agents from your org, see [Configure Your Agent](https://help.salesforce.com/s/articleView?id=ai.agent_parent_configure.htm) and [Deploy Your Agents](https://help.salesforce.com/s/articleView?id=ai.agent_parent_deploy.htm) in Salesforce Help. To configure or deploy agents at the command line, see the [Agentforce DX](https://developer.salesforce.com/docs/ai/agentforce/agent-dx/agent-dx.md) documentation. Also, refer to the [Metadata API types associated with Agentforce](/docs/ai/agentforce/references/agents-metadata-tooling/agents-metadatav67.html). ## Test Agents There are various ways to test agents. To identify the testing method that is best for your use case, see [Get Started With Testing Agents](https://developer.salesforce.com/docs/ai/agentforce/testing-api/testing-api-get-started.md). **note:** Always test agents again after they're published. # Manage Agent Trace Files When you run an agent preview conversation (either interactive or programmatic), trace files are recorded and saved in your local DX project. Each customer utterance and agent response of a conversation creates trace data. Analyze the trace data to observe, monitor, investigate, and troubleshoot agent events and behavior. For a list of `agent trace` commands, see [Salesforce CLI agent trace Command Reference](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-trace-reference.md). ## See Also - [Preview and Debug an Agent](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-dx-nga-preview.md) # Manage an Agent with Agentforce DX You can activate or deactivate an agent right from VS Code or with a CLI command. ## Activate or Deactivate an Agent Activating an agent makes it available to users on the channels that your agent is connected to. Deactivating the agent ends its open interactions, and makes it unreachable for all connections. ### Use VS Code Commands 1. In VS Code, open your Salesforce DX project. 1. In Explorer, navigate in your DX project's package directory to one of the metadata component files that makes up your agent: - Bot (file extension `.bot-meta.xml` in the `bots` directory) - BotVersion (file extension `.botVersion-meta.xml` in the `bots` directory) 1. Right-click the metadata component file and select **AFDX: Activate Agent** or **AFDX: Deactivate Agent**. ![VS Code genAiPlannerBundle MD file open and commands to activate or deactivate the agent from a right-click.](https://developer.salesforce.com/media/dx-activate-agent-2.png '{"class": "image-lg"}') When activating an agent, if it has more than one version, you're prompted to select the version you want to activate. ### Use CLI Commands 1. Open a terminal (macOS, Linux) or command prompt (Windows) and change to your DX project directory. Or use the integrated terminal in VS Code. 2. Run the `agent activate` command to activate an agent in your org. Specify the `--target-org` flag if you haven't set the org as your default. For example: ```bash sf agent activate --target-org my-org ``` The command displays the agents that are currently inactive. Use the arrow keys to select the agent you want to activate, then press Return. If there are multiple versions of the agent, you're prompted for the version you want to activate. If you know the version and API name of your agent, you can use the `--version` and `--api-name` flags to immediately activate it without being prompted. Run the `agent deactivate` command in a similar way to deactivate active agents. ## Open an Agent in Agentforce Builder in Your Org You can open an agent directly in your org's Agentforce Builder UI from VS Code or with a CLI command. ### Use VS Code Commands 1. In VS Code, open your Salesforce DX project. 1. In Explorer, navigate to your agent's `.agent` file or the metadata file in the `aiAuthoringBundle` directory of your DX project's package directory. 1. Right-click the file and select **AFDX: Open Authoring Bundle in Default Org**. If the agent has more than one version, you're prompted to select the version you want to open. ### Use CLI Commands 1. Open a terminal (macOS, Linux) or command prompt (Windows) and change to your DX project directory. Or use the integrated terminal in VS Code. 1. Run the `org open agent` command to open an agent in your org's Agentforce Builder UI. Specify `--target-org` if you haven't set the org as your default. - To open an agent by its API name: ```bash sf org open agent --api-name Local_Agent_Info ``` - To open an agent by its authoring bundle API name, use the `--authoring-bundle` flag. ```bash sf org open agent --authoring-bundle Local_Agent_Info ``` To open a specific version, use the `--version` flag and a version number, such as `--version 2`. By default, the org opens in your default browser. Use `--browser` to specify `chrome`, `edge`, or `firefox`. To open in incognito mode, add `--private`. To display the navigation URL without launching a browser, add `--url-only`. # Manage Conversations in React Native Learn how to launch, manage, and enrich Agentforce conversations in your React Native application. ## Launch a Conversation There are two methods for opening the conversation UI: ### launchConversation() Opens the conversation UI. If an existing conversation is available, it's preserved and the user can continue where they left off. ```tsx import { AgentforceService } from "@salesforce/react-native-agentforce"; // Must configure first await AgentforceService.configure({ /* ... */ }); // Launch -- resumes existing conversation if available await AgentforceService.launchConversation(); ``` This is the recommended method for most use cases. It avoids discarding conversation history and provides a smoother user experience. ### startNewConversation() Closes any existing conversation and starts fresh. The previous conversation is terminated and a new one is created. ```tsx // Force a fresh conversation await AgentforceService.startNewConversation(); ``` Use this when you explicitly want to discard the previous conversation, for example, when the user switches accounts, resolves an issue, or navigates to a different context. ### Preconditions Both methods require: 1. The SDK must be configured via `configure()`. If not, the native module rejects with `NOT_CONFIGURED`. 2. On Android, a current Activity must be available. If not, the promise rejects with `ERROR: Activity not available`. ### Error Handling ```tsx try { await AgentforceService.launchConversation(); } catch (error) { // error.code can be: // 'NOT_CONFIGURED' -- configure() was not called // 'LAUNCH_ERROR' -- SDK failed to start session (iOS) // 'ERROR' -- general error (Android) console.error("Launch failed:", error.message); } ``` ## Close a Conversation Terminate the current conversation and dismiss the conversation UI: ```tsx const success = await AgentforceService.closeConversation(); ``` The user can also close the conversation by: - **iOS**: Tapping the close button in the chat view's top bar - **Android**: Tapping the back arrow in the toolbar ## Conversation Lifecycle Understanding how conversations are managed helps you build better user experiences. ### Conversation Reuse Calling `launchConversation()` multiple times reuses the same conversation object. This means: - The user sees their previous messages when re-opening the chat. - The agent retains context from the ongoing session. - Additional context set earlier is still active. ### When Conversations are Cleared Conversations are cleared when: - `closeConversation()` is called - `startNewConversation()` is called - `resetSettings()` is called (clears everything) - Switching modes (for example, calling `configure()` with `type: 'employee'` after previously configuring `type: 'service'`) - `setEmployeeAgentId()` is called with a different agent ID (iOS only) ## Additional Context Additional context provides contextual information to the Agentforce agent during a conversation. This helps the agent deliver more personalized and relevant responses. **note:** `setAdditionalContext()` must be called after `launchConversation()` or `startNewConversation()`. The context is set on the active conversation object, which doesn't exist until a conversation is launched. ### Basic Usage ```tsx // Step 1: Launch conversation await AgentforceService.launchConversation(); // Step 2: Set context await AgentforceService.setAdditionalContext({ variables: [ { name: "userId", type: "Text", value: "005xx0000001234" }, { name: "accountId", type: "Text", value: "001xx0000001234" }, { name: "priority", type: "Text", value: "high" }, ], }); ``` ### Context Variable Types | Type | Description | Example Value | | ---------- | ---------------------------- | --------------------------------------- | | `Text` | String value | `'Jane Smith'` | | `Number` | Numeric value | `15234.56` | | `Boolean` | True/false | `true` | | `Date` | ISO date string | `'2024-01-15'` | | `DateTime` | ISO datetime string | `'2026-03-11T10:30:00.000Z'` | | `Json` | JSON data (object or string) | `{ language: 'en' }` | | `List` | Array value | `['ORD-001', 'ORD-002']` | | `Money` | Monetary value | `50000` | | `Object` | Key-value map | `{ street: '123 Main St', city: 'SF' }` | | `Ref` | Reference value | `'003xx0000001234AAA'` | | `Variable` | Generic variable | `'sess_abc123'` | ### Validation Rules The bridge validates context variables before sending them to the native SDK: - **Type names are case-sensitive.** Use `'Text'` not `'text'`, `'Boolean'` not `'boolean'`. Invalid types cause an error. - **Each variable must have a non-empty `name` and `type`.** Missing fields cause an `INVALID_CONTEXT` error. - **Validation errors are thrown synchronously** before the native call, so you can catch them immediately. - **The `description` field is only supported on Android.** On iOS, it's silently ignored. ### Complete Example with All Types This example demonstrates all 11 context variable types: ```tsx await AgentforceService.setAdditionalContext({ variables: [ // Text -- simple string value { name: "customerName", type: "Text", value: "Jane Smith", }, // Number -- numeric value (double precision) { name: "accountBalance", type: "Number", value: 15234.56, }, // Boolean -- true/false { name: "isVIPCustomer", type: "Boolean", value: true, }, // Date -- ISO date string { name: "memberSince", type: "Date", value: "2024-01-15", }, // DateTime -- ISO datetime string with timezone { name: "lastInteraction", type: "DateTime", value: "2026-03-11T10:30:00.000Z", }, // Json -- JSON data (can be string or object) { name: "preferences", type: "Json", value: { language: "en", timezone: "America/Los_Angeles", notifications: true, }, }, // List -- array of values { name: "recentOrderIds", type: "List", value: ["ORD-2026-001", "ORD-2026-002", "ORD-2026-003"], }, // Money -- monetary value { name: "creditLimit", type: "Money", value: 50000, }, // Object -- key-value map { name: "shippingAddress", type: "Object", value: { street: "123 Market Street", city: "San Francisco", state: "CA", zip: "94105", country: "US", }, }, // Ref -- reference to another record { name: "primaryContactId", type: "Ref", value: "003xx0000001234AAA", }, // Variable -- generic variable { name: "sessionToken", type: "Variable", value: "sess_abc123def456", }, // With description (Android only, ignored on iOS) { name: "currentCaseId", type: "Text", value: "500xx0000009876AAA", description: "The active support case for this customer", }, ], }); ``` **note:** The `description` field is only supported on Android. On iOS, it's ignored. ## Hidden Prechat Fields Hidden prechat fields let you pass values to the Service Agent prechat form without displaying them to the user. Common use cases include pre-populating a `ContactId`, `AccountId`, or session token. **warning:** Android Limitation On Android, hidden prechat fields are stored but **not sent** to the native SDK during session initialization. This feature is fully functional on iOS only. If hidden prechat fields are critical to your use case, use iOS or wait for a future bridge update. **note:** Hidden prechat fields only apply to **Service Agent** conversations. They have no effect for Employee Agent conversations. ### Usage Register hidden prechat fields **before** calling `launchConversation()`: ```tsx // Step 1: Register hidden prechat fields await AgentforceService.registerHiddenPreChatFields({ ContactId: "003xx0000001234AAA", AccountId: "001xx0000005678AAA", Subject: "Mobile App Support Request", }); // Step 2: Launch conversation await AgentforceService.launchConversation(); ``` ### Reading and Clearing Fields ```tsx // Read current fields const fields = await AgentforceService.getHiddenPreChatFields(); console.log(fields); // { ContactId: '003xx...', AccountId: '001xx...' } // Clear all fields await AgentforceService.clearHiddenPreChatFields(); ``` ### Complete Hidden Prechat Example This example shows the full flow of configuring, registering hidden fields, and launching: ```tsx import React, { useState } from "react"; import { View, Button, Text, Alert, StyleSheet } from "react-native"; import { AgentforceService, HiddenPreChatFields } from "@salesforce/react-native-agentforce"; export default function ServiceAgentWithPrechat() { const [currentFields, setCurrentFields] = useState({}); const handleLaunchWithFields = async () => { try { // Step 1: Configure await AgentforceService.configure({ type: "service", serviceApiURL: "https://mycompany-support.my.salesforce-scrt.com", organizationId: "00Dxx0000001234EAA", esDeveloperName: "My_Service_Agent", }); // Step 2: Register hidden fields (before launch) await AgentforceService.registerHiddenPreChatFields({ ContactId: "003xx0000001234AAA", AccountId: "001xx0000005678AAA", Subject: "Mobile App Support", Origin: "Mobile", Priority: "High", }); // Read back to verify const fields = await AgentforceService.getHiddenPreChatFields(); setCurrentFields(fields); // Step 3: Launch -- hidden fields are sent during session initialization await AgentforceService.launchConversation(); } catch (error) { Alert.alert("Error", String(error)); } }; const handleClearFields = async () => { await AgentforceService.clearHiddenPreChatFields(); setCurrentFields({}); }; return ( Hidden Prechat Fields {Object.entries(currentFields).map(([key, value]) => ( {key}: {value} ))} {Object.keys(currentFields).length === 0 && ( No fields registered )}