Agentforce Voice companion forms¶
Status: Current | Last reviewed: 2026-09-29
Use this handoff to explain or extend the Add a Driver / Add a Vehicle demo:
Agentforce Voice manages the conversation, an AWS service manages the companion
form, and Agent Script runs bounded short checks for the submitted result.
The original TrueServe Auto Voice Demo (TS_Auto_Voice_Demo) is active on
version 5 in the ccaas org as of the review date.
The Salesforce-native clone uses separate Apex actions, authenticated LWR forms and native messaging. This page describes the original AWS/MCP implementation.
Explanation to share¶
Agentforce calls an AWS-hosted MCP service through Apex actions. That service creates a shared experience, texts a private link, and renders the selected Auto Club Group form. The app posts its submission to the service. Agent Script opens the form immediately, then runs short status checks with deterministic transitions between them. A submitted result returns through the action and the agent acknowledges it without the customer saying “done.” New voice turns refresh form status and restart the bounded checking window.
Components and ownership¶
flowchart LR
caller["Customer"]
app["Companion web app<br/>ACG driver / vehicle forms"]
subgraph salesforce["Salesforce"]
voice["Agentforce Voice<br/>Agent Script v5"]
apex["Apex invocable actions<br/>TrueServeAutoMCP credential"]
end
subgraph aws["AWS demo"]
edge["Global Accelerator<br/>HTTPS ALB"]
mcp["multimodal-service<br/>MCP + REST + SSE"]
state["PostgreSQL: sessions<br/>Redis: forms, events, results"]
sms["End User Messaging SMS"]
end
caller <-->|Speech| voice
voice <-->|Action calls and results| apex
apex <-->|OAuth MCP| edge
edge <--> mcp
mcp <--> state
mcp -->|Send private link| sms
sms -->|Text message| caller
caller -->|Open link| app
app <-->|Session-scoped REST and SSE| edge
Diagram source: agentforce-voice-companion-forms.mmd.
| Component | Responsibility |
|---|---|
| Agentforce Voice and Agent Script | Voice dialogue, consent, workflow selection, bounded checks, receipt acknowledgement |
| Apex adapters | Typed action inputs/outputs and synchronous MCP callouts through TrueServeAutoMCP |
multimodal-service |
Connection links, SMS requests, form rendering, validation, submission results |
| Companion app | Display forms and send authenticated submissions over REST; receive rendering events over SSE |
| PostgreSQL and Redis | Session metadata in PostgreSQL; form state, events, deduplication and retained results in Redis |
The deployed app is the standalone demo web app,
served at /demo/. It uses the separate
acg-auto catalog
with ACGAddDriverForm and ACGAddVehicleForm. You can build a custom mobile
client against the same REST/SSE contract; that client integration is additional
work. The existing demo does not require a native mobile SDK.
The AWS demo runs the service, PostgreSQL and Redis in separate containers on one EC2 host behind Global Accelerator and the HTTPS ALB. It is a single-host demo with expiring state. See the deployment notes before reproducing it, including the current short-wait image requirement.
Connection and submission flow¶
- Resolve the mobile number.
ANIis optional linked context fromVoiceCall.FromPhoneNumber; Agent Studio/API callers can supply$Context.ANI. If absent, the agent asks for a mobile number including country code. - Connect after consent.
connect_experiencecreates the experience and requests an AWS text containing its private link. The agent stores the returnedexperienceSessionIdinternally. Customers never supply that ID.sms_submittedmeans AWS accepted the request, not confirmed handset delivery. - Attach the app. The URL carries an opaque code in its fragment. The app
redeems it at
/v1/connections/redeemfor a scoped browser JWT, then subscribes to/v1/sessions/{id}/events. MCP credentials stay on the servers. - Open immediately.
open_formrenders the requested component and returnssurfaceIdandstatuswithwaitForForm=false. Driver and Vehicle reuse the same experience and link, with surfacesauto-driverandauto-vehicle. - Check while the form is open. Agent Script runs the short-check cycle below. The agent can answer field questions on new voice turns.
- Submit from the app. The app sends the validated action envelope to
POST /v1/sessions/{id}/ui-action. The service validates and retains the terminal result. An outstanding check returns it, or the next check reads it. - Acknowledge the result.
report_statussummarizes the validated receipt. Neither a spoken completion cue nor a second Voice session is required.
The experience ID identifies shared form state. It is distinct from the
Salesforce Voice session ID and the MCP transport session ID. Internal variables
also hold the private appUrl, active surface, mode, result and check counter.
Salesforce action contract¶
| Agent Script action | Apex adapter | MCP tool |
|---|---|---|
connect_experience |
TSAutoMcpConnect |
connect_auto_experience |
open_form / open_spoken_intake |
TSAutoMcpStart |
start_auto_change |
check_form |
TSAutoMcpAwait |
await_auto_change |
submit_spoken |
TSAutoMcpSpoken |
submit_spoken_auto_change |
The tested execution path uses these Apex adapters and the
TSAutoMcpClient
helper. Although the MCP tools are registered in Salesforce, the current script
targets apex://... actions. TrueServeAutoMCP supplies the OAuth-authenticated
MCP connection. You need the corresponding runtime-user permissions described
in the Salesforce setup guide.
The Agent Script pattern that worked¶
The full script separates conversational reasoning from deterministic checks:
auto_intake.before_reasoningresets the counter and reads any active app result immediately withwaitSeconds=0.auto_intake.after_reasoningtransitions tomonitor_formin app mode.monitor_form.before_reasoningwaits up to two seconds, then transitions directly to another check orreport_status. It bypasses LLM reasoning between checks, avoiding repeated speech.report_statusacknowledgescompleted_demoorcancelled. At the limit,pendingonly means that the form remains open.
The checking block is an excerpt of the deployed script:
before_reasoning:
run @actions.check_form
with experienceSessionId = @variables.experienceSessionId
with surfaceId = @variables.activeSurfaceId
with waitSeconds = 2
set @variables.formResult = @outputs.resultJson
set @variables.formStatus = @outputs.status
set @variables.checkCount = @variables.checkCount + 1
if @variables.formStatus == "pending" and @variables.checkCount < 30:
transition to @subagent.monitor_form
else:
transition to @subagent.report_status
Version 5 allows 30 checks per turn, giving roughly 60 seconds of wait budget plus action overhead. A two-second wait is not a two-second response guarantee. Each call remains synchronous, and speech has not been shown to cancel an individual call early.
Salesforce's reasoning-hook reference
allows actions and transitions in these blocks. after_reasoning runs when
reasoning exits; it is not a callback for the end of audio playback. Prompt
instructions guide consent, questions and intake mode; the script controls
the repeated checks.
The app submission happens independently of the conversation, but Salesforce receives it as an ordinary action result. This implementation does not use the outbound asynchronous action pattern to resume an idle Voice session. It needs no transcript observer, hidden audio, or join to an existing LiveKit room.
Boundaries and evidence¶
Silent submission is detected during the checking window. After the window, the result remains stored within the session lifetime, but a new voice turn may be needed to read it. This is not indefinite background monitoring or an idle Voice push callback.
Explicit spoken intake uses the same action contract: sendLink=false
creates an experience without a text, and complete, confirmed details use
submit_spoken_auto_change. Partial spoken fields do not update the visible
form. Switching from spoken intake back to app entry calls open_form again
to rearm checks. All receipts are demonstrations; no policy or coverage changes.
| Validation on 2026-09-22 | What the evidence establishes |
|---|---|
| Main demo v5, live authoring actions | Agent-created experience; Vehicle submitted after 45 seconds; Driver submitted on the same experience; two receipts without completion speech |
| Main demo v5, published Voice entry | Missing ANI prompts for a mobile number, not an experience ID |
Diagnostic TS_Auto_Voice_MCP_Probe v6, published Voice |
In one call, a field question received an audio answer in about 4.1 seconds, then silent form submission received receipt audio in about 3.2 seconds |
| Salesforce validation | Agent Script validated/published; 18 Apex tests passed for the main upgrade |
The diagnostic used eight short checks per request and its own Agent API/LiveKit Voice connection. Its timings are approximate observations, not service limits. The main demo uses thirty checks; its delayed-form test used the live authoring SDK. Supplied ANI was checked with simulated actions. No real SMS was sent in these upgrade tests. The full current flow still needs authenticated Agent Builder, handset delivery and PSTN/SIP acceptance testing.
Recorded evidence: main customer flow and same-call Voice/form diagnostic.