Skip to content

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:

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=true for parent-plus-Task creation and child-plus-parent-summary writes.
  • Readback after writes. When a write throws, writeAndRead reads 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.

  1. Validate the conversation UUID, agent base ID 4463, and normalized DNIS 8044136534.
  2. Normalize phone numbers to digits, removing a leading US 1 from an 11-digit value.
  3. Query Person Accounts using the last four ANI digits as a candidate filter, plus the fixed Denise Account 001DW00001ZuvWYYAZ.
  4. Reject more than 200 returned candidates. Match candidates against the full normalized Phone or PersonMobilePhone.
  5. Reject multiple exact matches. Return the unique matching Account, or Denise if none matches. Missing Denise does not block a valid match.
  6. 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.

  1. Validate the selected Account and Contact IDs and acquire the call lock.
  2. Query the parent by its exact :parent external key, including its call Tasks and child Cases.
  3. If missing, create the parent Case and inbound Task in one Composite transaction. The Task uses @{parent.id} to reference the new Case.
  4. If the parent exists without a call Task, verify coordinator ownership and upsert the missing Task by its :interaction external key.
  5. Read back one open parent and exactly one matching voice Task. Check external key, Account/Contact, Task WhatId, WhoId, and CallObject.
  6. 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.

  1. Validate that the supplied context belongs to the conversation.
  2. Query CareProgramEnrollees in every care program with a CareProgramTeamMember whose AccountId is the coordinator Account.
  3. Require 1–500 enrollee rows. Validate Person Accounts, deduplicate by Account ID, sort by ID, and assign per-call references p1, p2, etc.
  4. For each patient, query their latest CareRequest using MemberId, ordered by RequestedDate DESC NULLS LAST, Id, LIMIT 1. Run at most four requests concurrently.
  5. 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.
  6. Build the roster's reason and optional Contact, CareRequest and source Case links.
  7. 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.

  1. Validate call context, a unique pN reference and Account ID, disposition, nonempty reason, and optional record IDs.
  2. Require acceptance for escalation. The handler checks the supplied acceptance value; it does not independently read the caller transcript.
  3. Acquire the call lock and read the parent, Task and children.
  4. Validate every existing child against this call's external key, patient roster, parent links, reason, status flags, and expected optional source links.
  5. Find the existing child by patient Account ID.
  6. Apply monotonic progression: discussed < completed < escalated. A delayed earlier update cannot reopen a completed inquiry or undo escalation.
  7. Build the proposed child fields and HTML summary. Create/update the child and update parent HTML in one Composite transaction.
  8. 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.

  1. Merge nested sessionEnd.params with top-level ending fields; top-level values win.
  2. With background updates enabled, inspect tenant/call-scoped jobs marked roster_patient and legacy workflow 1855 jobs.
  3. Poll every 500 milliseconds for up to 30 seconds, outside the call lock. Use the latest run status where available.
  4. Count nonterminal jobs as pending. Count terminal jobs as failed/unverified unless status is completed and output verified=true.
  5. Acquire the call lock and read the parent. Return ok=true, linked=false if no parent exists.
  6. Require an open parent and valid Task. Current code then closes every child with Status=New, before full child receipt validation.
  7. 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.
  8. PATCH the Task summary. Set Task status to In Progress only when String(session_escalated) === "true"; otherwise set Completed.
  9. Close the parent unless the same escalation condition is true. Missing escalation data therefore takes the closing branch.
  10. Release the lock, then query VoiceCall by VendorCallKey LIKE '%:<conversationId>:call.%'. Try four times with two-second gaps.
  11. 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.

  1. Resolve a uniquely matching fixed patient name from the supplied roster.
  2. Thomas maps to StepTherapyAppeal, Closed, and a fixed completed-inquiry description.
  3. Renee maps to PriorAuthorizationFollowUp, Escalated, and a fixed accepted-handoff description; acceptance is mandatory.
  4. Lock/read/validate the call. Create one child using :outcome:thomas or :outcome:renee, plus parent HTML atomically.
  5. 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.

See also