Takeda Genesys call action logic¶
Status: Historical MCP audit | Last reviewed: 2026-10-07
The native replacement is documented in Takeda native Salesforce workflows, including the controls for each mapping and the revised completion rule. The audit below describes the earlier MCP path and remains relevant to retained legacy versions.
Use this reference to understand each takeda_genesys_call_actions operation and decide which logic belongs in a workflow. The field mapping and correctness audit lists the exact Salesforce destinations, summary variants, and known problems. This describes the Vanguard AI route for agent 4463; the direct-to-human backup number has separate Genesys Salesforce Data Actions.
Where you control the behavior¶
| Control | Current owner |
|---|---|
| Call-start/end workflow selection | Agent 4463's config.lifecycle |
| Action order, branches, inputs and workflow outputs | Published workflow configuration |
| Patient selection and when an inquiry is discussed/completed | Agent prompts and workflow-tool arguments |
| Trusted call context, escalation disposition and completion marker | Agent tool bindings |
| Salesforce integration, object fields, defaults, queries and write checks | Custom TypeScript handler |
| Parent Case HTML, patient badges and handoff wording | Shared TypeScript summary renderer |
| Human wrap-up defaults, Customer Intents and proposed follow-up Tasks | Salesforce Apex and wrap-up components |
There is no single mapping screen for this implementation. Changing an Action's input does not change a field mapping embedded in its handler. A published workflow pins its graph, but does not pin the MCP implementation: changing the served handler changes behavior for every workflow version calling it.
Start with these sources:
- Workflow definitions:
simpleStart,simpleEnd, and legacysimpleReceipt. - Patient workflow and agent bindings:
rosterPatientWorkflow,rosterPatientTool,dynamicPatientVoice. - Action implementation: the six functions below.
- Summary renderer:
renderSummaryHtmlandcaseBadge. - Salesforce human wrap-up:
applyTakedaDefaultsandgetTakedaSummary.
Edit workflow/agent drafts in Studio and publish the intended versions to change their configuration. Changing handler or renderer code requires that code to be served by ai-manager; publishing a workflow alone does not deploy it. Changing Salesforce Apex is a separate Salesforce deployment.
Inspected configuration¶
The read-only Vanguard inspection on October 7 found:
| Asset | Version and behavior |
|---|---|
| Voice agent | 4463:v28; start 1856, completion 1857, startup timeout 45 seconds |
| Start workflow | 1856:v5; three Actions, one router, two assignments; synchronous |
| Patient workflow | 1918:v1; one Action; asynchronous |
| End workflow | 1857:v7; one Action; asynchronous |
| Legacy patient workflow | 1855:v5; fixed Thomas/Renee outcomes; asynchronous |
| MCP tool | 63ee3079-d047-4f30-b982-205522ce924c; expose_to_agents=false |
The MCP endpoint is https://ai-manager.vanguard.dev.trueserve.deloitte.com/api/mcp/takeda. It runs inside ai-manager, through the authenticated route.
The workflow authenticates to that endpoint using Clearway workflow action authentication, referenced by the MCP tool configuration. The handler separately uses TrueServe Dev SDO, integration f28f65a9-0598-47df-8d08-77f7282a8f09, for Salesforce JWT authentication. The Salesforce integration ID and permitted tenant are fixed in code. See the Salesforce client.
Shared execution rules¶
The route requires a tenant API token with agents:run and the configured tenant. Workflow nodes explicitly select an operation through parameters.tool_method. The voice agent receives the two workflow tools, not this MCP tool directly.
The implementation uses:
- A UUID call identity and 18-character Salesforce IDs.
- Stable external keys:
takeda:<tenant>:genesys:<conversationId>:<suffix>. - A PostgreSQL advisory transaction lock per conversation around record preparation, patient writes, and finalization writes.
- Salesforce Composite with
allOrNone=truefor parent-plus-Task creation and child-plus-parent-summary writes. - Readback after writes. When a write throws,
writeAndReadreads immediately, then after 250, 750 and 1,500 milliseconds to determine whether it committed. It does not blindly repeat the create. - An eight-second timeout per Salesforce HTTP request, a four-minute local token cache, and one token-refresh retry on HTTP 401.
These are not universal guarantees for every branch. Legacy missing-Task recovery and several finalization PATCHes do not use the same uncertain-write reconciliation. Finalization has the specific defects documented in the audit.
On an action exception, the route returns MCP isError=true and a JSON result containing ok=false, verified=false, contextStatus=unavailable, and an error message. A workflow run being terminal does not by itself establish that records were verified.
Action 1: find the coordinator¶
Operation: takeda_lookup_coordinator → lookupCoordinator.
Inputs: conversationId, ani, dnis, agentId, mapped from input.conversation_id, input.ani, input.dnis, input.agent_id.
- Validate the conversation UUID, agent base ID
4463, and normalized DNIS8044136534. - Normalize phone numbers to digits, removing a leading US
1from an 11-digit value. - Query Person Accounts using the last four ANI digits as a candidate filter, plus the fixed Denise Account
001DW00001ZuvWYYAZ. - Reject more than 200 returned candidates. Match candidates against the full normalized
PhoneorPersonMobilePhone. - Reject multiple exact matches. Return the unique matching Account, or Denise if none matches. Missing Denise does not block a valid match.
- Validate the selected Account is a named Person Account with a Person Contact.
Writes: none.
Outputs: ok, matched, account, fallback. Each Account projection contains id, name, contactId.
The workflow router chooses lookup.account or lookup.fallback and assigns it to vars.coordinator. Failure takes neither success branch. Empty or unmatched ANI can select the demo fallback; ANI matching is identification for this demo, not caller authentication.
Workflow fit: Salesforce query → assignment for normalization/matching → router. Preserve the unique-match and incomplete-result checks.
Action 2: prepare the call records¶
Operation: takeda_prepare_call_records → prepareCall.
Inputs: current conversationId and vars.coordinator as account.
- Validate the selected Account and Contact IDs and acquire the call lock.
- Query the parent by its exact
:parentexternal key, including its call Tasks and child Cases. - If missing, create the parent Case and inbound Task in one Composite transaction. The Task uses
@{parent.id}to reference the new Case. - If the parent exists without a call Task, verify coordinator ownership and upsert the missing Task by its
:interactionexternal key. - Read back one open parent and exactly one matching voice Task. Check external key, Account/Contact, Task
WhatId,WhoId, andCallObject. - Return verified identity and an initial transfer projection.
Writes: parent Case and Task fields in the mapping tables.
Outputs: ok, callContext, transferParams. No patient outcome is claimed at startup.
Workflow fit: query → existence/ownership branches → atomic create → readback → verification → assignments. Two independent create nodes would lose the current all-or-none behavior.
Action 3: load the patient roster and facts¶
Operation: takeda_load_call_patients → loadPatientContext.
Inputs: current conversationId and records.callContext.
- Validate that the supplied context belongs to the conversation.
- Query CareProgramEnrollees in every care program with a CareProgramTeamMember whose
AccountIdis the coordinator Account. - Require 1–500 enrollee rows. Validate Person Accounts, deduplicate by Account ID, sort by ID, and assign per-call references
p1,p2, etc. - For each patient, query their latest CareRequest using
MemberId, ordered byRequestedDate DESC NULLS LAST, Id,LIMIT 1. Run at most four requests concurrently. - Query only the Cases referenced by those requests. Include up to 100 Tasks and 100 Events per source Case modified in the last 30 days.
- Build the roster's reason and optional Contact, CareRequest and source Case links.
- Build a text brief from returned facts. Preserve uncertainty in recorded cause notes; absence of a request is stated explicitly.
Writes: none. It does not change the historical CareRequest, source Case, or submission activity.
Outputs: ok, contextStatus, coordinatorFirstName, patientBrief, enriched callContext, initial transferParams.
The workflow projects only its five configured outputs. Its transfer_params comes from records.transferParams, not a patient-save result.
Workflow fit: Salesforce roster query → transform/deduplicate → bounded patient iteration → linked Case query → text/context assignment. Avoid a global LIMIT 1 across all patients or a broad historical Case scan.
Policy boundary: this query unions all matching programs and does not filter active enrolment/team membership. Decide whether that is the intended scope before reusing it outside this demo.
Action 4: save a roster patient's inquiry¶
Operation: takeda_save_roster_patient → saveRosterPatientOutcome.
Inputs: workflow 1918 maps trigger._conversation_id, trigger.callContext, trigger.patientRef, trigger.disposition, trigger.handoffAccepted.
The host binds the verified call_context and _case_write_kind=roster_patient. The record tool allows discussed or completed; the escalation tool binds escalated and requires handoffAccepted=true. The patient reference is selected from the returned roster.
- Validate call context, a unique
pNreference and Account ID, disposition, nonempty reason, and optional record IDs. - Require acceptance for escalation. The handler checks the supplied acceptance value; it does not independently read the caller transcript.
- Acquire the call lock and read the parent, Task and children.
- Validate every existing child against this call's external key, patient roster, parent links, reason, status flags, and expected optional source links.
- Find the existing child by patient Account ID.
- Apply monotonic progression:
discussed<completed<escalated. A delayed earlier update cannot reopen a completed inquiry or undo escalation. - Build the proposed child fields and HTML summary. Create/update the child and update parent HTML in one Composite transaction.
- Read back and verify child state, relationships and summary. Repair an HTML mismatch and verify it again if necessary.
Outputs: verified, patientRef, patientAccountId, caseId, effective disposition, reused, summarySaved, callContext, transferParams.
Workflow 1918 retains only verified, patientRef, caseId, disposition. Its voice-facing workflow tools have empty output_mapping; they return submission/execution information immediately. The richer saved transfer projection does not update the voice session.
Workflow fit: validate → serialize by call → read/verify → calculate target status → atomic child/summary write → read/verify → output. Keep acceptance, identity and progression checks explicit.
Action 5: finish the call¶
Operation: takeda_finish_call_records → finishCall.
Inputs: trigger.conversation_id, trigger.session_end_params, backgroundUpdates=true, and the current trigger.session_variables.call_context if present, otherwise trigger.session_metadata.call_context.
- Merge nested
sessionEnd.paramswith top-level ending fields; top-level values win. - With background updates enabled, inspect tenant/call-scoped jobs marked
roster_patientand legacy workflow 1855 jobs. - Poll every 500 milliseconds for up to 30 seconds, outside the call lock. Use the latest run status where available.
- Count nonterminal jobs as pending. Count terminal jobs as failed/unverified unless status is
completedand outputverified=true. - Acquire the call lock and read the parent. Return
ok=true, linked=falseif no parent exists. - Require an open parent and valid Task. Current code then closes every child with
Status=New, before full child receipt validation. - In background mode, validate receipts and derive a plain-text summary from their status. Add pending/failed-job counts. Parent HTML is repaired here only when the finalizer closed at least one child.
- PATCH the Task summary. Set Task status to
In Progressonly whenString(session_escalated) === "true"; otherwise setCompleted. - Close the parent unless the same escalation condition is true. Missing escalation data therefore takes the closing branch.
- Release the lock, then query VoiceCall by
VendorCallKey LIKE '%:<conversationId>:call.%'. Try four times with two-second gaps. - Reject ambiguity or a conflicting
RelatedRecordId; otherwise PATCH the matching VoiceCall.
Outputs: ok, linked, optional reason, pendingUpdates, failedUpdates.
Read this as implementation, not a correctness guarantee. The premature closure, validation order, retry failure and summary repair gap are reproduced in the audit. Task/VoiceCall/final parent writes are acknowledged but not independently read back.
Workflow fit: job reconciliation → validated record snapshot → explicit ending-policy branch → summary/write transaction → verified final state → bounded VoiceCall lookup/update. A migration should correct the confirmed defects, not copy them.
Action 6: legacy fixed-patient outcome¶
Operation: takeda_save_call_outcome → savePatientOutcome.
Workflow 1855:v5 supplies outcome=thomas|renee, call context, conversation identity and optional acceptance. The current agent's two patient tools call workflow 1918 instead.
- Resolve a uniquely matching fixed patient name from the supplied roster.
- Thomas maps to
StepTherapyAppeal,Closed, and a fixed completed-inquiry description. - Renee maps to
PriorAuthorizationFollowUp,Escalated, and a fixed accepted-handoff description; acceptance is mandatory. - Lock/read/validate the call. Create one child using
:outcome:thomasor:outcome:renee, plus parent HTML atomically. - Reuse an existing receipt; verify the child and resulting HTML before returning.
The legacy create does not populate the generic path's optional patient Contact, CareRequest and source Case links. Outputs include verified, caseId, reused, summarySaved, thomasSaved, reneeSaved, callContext, transferParams. The legacy workflow exposes only verified.
Keep it only for callers still using legacy versions; it is not the model for a configurable patient workflow.
Moving the implementation into workflows¶
The native Salesforce node already supports queries, create/update/upsert operations, and bounded empty-query retries. It uses the Salesforce integration directly. The older start definition and end definition show this structure, but do not contain all current roster and reconciliation behavior.
| Concern | Existing fit | Work still required for equivalent behavior |
|---|---|---|
| Field mappings/defaults | Salesforce node fields, assignment, router |
Put the tables into explicit configuration |
| Caller matching and output projections | Queries, JSONata assignments, routers | Preserve ambiguity and completeness gates |
| Patient request loading | Queries and bounded iteration/parallel branches | Preserve per-patient latest-request semantics |
| Child status decisions | Assignment and router | Separate confirmed completion from disconnect |
| Parent/Task and child/summary atomicity | Existing Salesforce client can issue requests | Native Salesforce node has no Composite operation |
| Same-call concurrent writes | Current handler's advisory lock | Equivalent serialization or atomic server-side logic |
| Uncertain write acknowledgments | Exact external-key reads | Explicit reconciliation before retrying creates |
| Background job reconciliation | Current handler queries workflow execution/run tables | A supported status/reconciliation operation |
| HTML generation | Pure renderer today | A reusable escaped template/transform |
| VoiceCall retry | Native Salesforce query retry support | Idempotent finalizer and final readback |
The generic HTTP Request node does not itself implement this Salesforce JWT token-refresh path. Pointing it at /composite with a copied access token is not an equivalent replacement.
An efficient target keeps business mappings in visible Salesforce/assignment/router nodes and adds a reusable native Salesforce Composite operation, call-scoped serialization, and a supported job-reconciliation operation. Keep the pure summary transform reusable. Those platform operations can remove the Takeda HTTP/MCP hop without exposing credentials or repeating sandbox startup for each field assignment.
For P patients, the current startup normally makes P + 6 Salesforce requests: caller lookup, parent lookup, one parent/Task Composite, parent readback, enrollee query, P latest-request queries and one linked-Case query. The last query is omitted if there are no source Cases. A normal changed patient save uses three requests: read, Composite, read. Additional repairs/retries increase these counts.
A smaller canvas does not establish lower latency. Compare Salesforce requests, sequential network round trips, lock hold time, MCP initialization, and workflow overhead on the same call/roster. Measure startup and background work separately.
Migration acceptance criteria¶
- Preserve exact call identity, source relationships and per-call external keys.
- Keep unknown/ambiguous patient references from producing children.
- Keep explicit acceptance and monotonic child status progression.
- Make each parent/Task or child/summary transaction all-or-none.
- Reconcile timeout-after-commit without duplicate creation.
- Keep unresolved/pending work open and permit late saves and finalizer retries.
- Keep incomplete/failed results visible in workflow outputs and summaries.
- Preserve the startup transfer contract unless Genesys and its consumers change together.
- Verify successful, disconnected, escalated, partial-failure, concurrent and repeated-finalization cases.