feat(workflows): port built-in data-capture workflows from python#2007
Merged
toubatbrian merged 2 commits intoJul 9, 2026
Conversation
Ports the built-in workflow tasks from python livekit-agents (livekit/agents beta/workflows) to the stable workflows namespace, following the warm_transfer.ts pattern (functional core + thin class wrapper): - GetEmailTask / createGetEmailTask (email_address.ts) - GetNameTask / createGetNameTask (name.ts) - GetPhoneNumberTask / createGetPhoneNumberTask (phone_number.ts) - GetDOBTask / createGetDOBTask (dob.ts) - GetAddressTask / createGetAddressTask (address.ts) - GetDtmfTask / createGetDtmfTask (dtmf_inputs.ts) - GetCreditCardTask / createGetCreditCardTask (credit_card.ts), composed of internal card number / expiration date / security code sub-tasks plus the cardholder name task via TaskGroup workflows/utils.ts gains the DtmfEvent enum with formatDtmf / dtmfEventToCode helpers and a shared resolveWorkflowInstructions that mirrors python's WorkflowInstructions.resolve on top of Instructions.resolveTemplate. TaskGroup.add now accepts factories returning typed AgentTask<T> so typed sub-tasks compose without casts. Notable JS adaptations: time values are milliseconds (dtmfInputTimeout defaults to 4000ms), GetDOBResult uses structured DateOfBirth / TimeOfBirth objects instead of datetime.date/time, and DTMF input uses rtc-node's RoomEvent.DtmfReceived. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3ZnFWr54AZysyyf4g5Dyd
🦋 Changeset detectedLatest commit: 5af519a The changes in this PR will be included in the next version bump. This PR includes changesets to release 36 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
|
- Skip TaskGroup chat-context summarization when the session runs a realtime model: TaskGroup.onEnter requires a standard LLM and would otherwise fail after all card details were collected. - Forward task-level overrides (llm, tts, stt, vad, turnDetection, tools, allowInterruptions) from createGetCreditCardTask into the card sub-tasks; previously they attached only to the outer placeholder task and sub-tasks silently ran with session defaults. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3ZnFWr54AZysyyf4g5Dyd
davidzhao
approved these changes
Jul 9, 2026
7 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Ports the built-in workflow tasks from python
livekit-agents(livekit/agents/beta/workflows/) to the stableworkflowsnamespace, following thewarm_transfer.tspattern (functional core + thin class wrapper). Stacked on #1982 (brian/expressive-mode) because these tasks depend on itsInstructionsmodality redesign (resolveTemplate, audio/text variants).Changes Made
email_address.ts—GetEmailTask/createGetEmailTask: regex validation, character-by-character read-back, dynamicconfirm_email_addresstool injectionname.ts—GetNameTask/createGetNameTask: first/middle/last collection flags,nameFormat, spelling verification, placeholder-arg cleanup ("null", quoted values, no-letters rejection)phone_number.ts—GetPhoneNumberTask/createGetPhoneNumberTask: E.164-style validation, grouped read-backdob.ts—GetDOBTask/createGetDOBTask: two-digit-year normalization, future-date rejection, optionalupdate_timetool viaincludeTimeaddress.ts—GetAddressTask/createGetAddressTask: template/persona instruction pattern shared with emaildtmf_inputs.ts—GetDtmfTask/createGetDtmfTask: wired to rtc-nodeRoomEvent.DtmfReceived, local debounce helper mirroring python'sutils.aio.debounced, stop-event handling, user/agent state-change pause/resumecredit_card.ts—GetCreditCardTask/createGetCreditCardTask: composes internal card-number (Luhn), expiration, and security-code sub-tasks plus the cardholderGetNameTaskthroughTaskGroup; shareddecline_card_capture/restart_card_collectiontools and the restart looputils.ts—DtmfEventenum withformatDtmf/dtmfEventToCode, and a sharedresolveWorkflowInstructionsmirroring python'sWorkflowInstructions.resolveon top ofInstructions.resolveTemplatetask_group.ts—TaskGroup.addnow accepts() => AgentTask<any>; the previousAgentTask<unknown>signature rejected typed tasks (TS invariance), which the credit-card composition needsport-builtin-workflows.md); all new tasks exported from theworkflowsnamespaceReview follow-ups (fixed, candidates for upstreaming to python):
GetCreditCardTaskskips TaskGroup chat-context summarization on realtime-model sessions (would otherwise fail after all card details were collected)llm,tts,stt,vad,turnDetection,tools,allowInterruptions) are forwarded fromcreateGetCreditCardTaskinto the card sub-tasksIntentional JS adaptations:
dtmfInputTimeoutdefaults to4000)GetDOBResultuses structuredDateOfBirth/TimeOfBirthobjects instead of python'sdatetime.date/time(avoids timezone pitfalls)instructions?: InstructionParts | Instructions | string(python'sWorkflowInstructionsclass becomes the existingInstructionPartsinterface)Pre-Review Checklist
pnpm build,pnpm lint,pnpm format:checkgreen;pnpm api:updatefor the core package fails identically on the base branch (pre-existing api-extractorexport * aslimitation), so no report changesTaskGroup.addsignature change is required by the credit-card composition, explained above)Testing
function_tools_executed+debug_messagelifecycle probes (task_started/task_resultemitted viaAgentSession._emitDebugMessage):GetEmailTask: spoken "john dot doe at gmail dot com" →update_email_address→ confirm → resultjohn.doe@gmail.comGetNameTask: name + spelling →update_name→ confirm →{firstName: "Brian", lastName: "Yin"}GetPhoneNumberTask: spoken digits →update_phone_number→ confirm →+14155551234GetDOBTask: "January fifteenth, nineteen ninety" →update_dob→ confirm →{year: 1990, month: 1, day: 15}GetAddressTask: full US address →update_address→ confirm → composed address stringGetDtmfTask: spoken digits →record_inputs→"1 2 3 4"GetCreditCardTask: full 4-sub-task TaskGroup run → composed result{issuer: "Visa", cardNumber, expirationDate: "04/30", securityCode: "321", cardholderName}; the mismatch → re-ask path (confirm_card_numberwith an STT-garbled repeat) and thedecline_card_capture→CardCaptureDeclinedErrorpropagation through TaskGroup were also exercised organicallyrestaurant_agent.ts/realtime_agent.tsplayground validation not run (additive change; no existing pipeline code paths modified except theTaskGroup.addtype signature)Additional Notes
The class wrappers (
new GetEmailTask().run()) delegate onlyrun(), matchingWarmTransferTask; compositions that needupdateChatCtx/updateToolson the task (e.g. insideTaskGroup) should use thecreate*Taskfunctional forms, ascreateGetCreditCardTaskdoes internally.Two observations from e2e (pre-existing, not introduced by this PR — reproduced independent of the workflow code):
SessionHostevent listeners register slightly after the first activity'sonEnterstarts, so events emitted very early inonEnter(e.g._emitDebugMessage) can be lost.undefinedoccur during AgentTask handoff/activity-drain phases (a plainbasic_agentconsole session produces none; any multi-AgentTasksession produces a few). Non-fatal when handled, but under Node's default--unhandled-rejections=throwit crashes the process — worth a follow-up.