* add trigger * small fixes * add missing workflow DTOs * small fixes * use activeOnWithChildren * fix active on when switching trigger type * remove add variable dropdown * feat: lang support * fix: type errors * feat: select voice agent * refactor: address feedback * refactor: address feedback * refactor: missing import * fix: types * add getAllWorkflowsFromRoutingForm to WorkflowService * fix error caused by undefined evt * fix type error * fix type error * fix tests * feat: add inbound calls * chore: formatting * chore * feat: finish inbound call * chore: formatting * fix: update bug * fix: types * code clean up * final fixes and clean up * remove console.log * remove template text form from triggers * add routing form repoditory function * refactor: Agent Configuration Sheet (#23930) * refactor: agent configuration sheet * chore: use default phone numbre * refactor: improvements * refactor: improvements * fix: types * fix: feedback * fix bug with key * chore: * fix: feedback * fix: prompt * add comments * fix: review * fix: review * refactor: class * refactor: class * fix test * allow cal ai action on form triggers * move any reusable code to scheduleAIPhoneCall * add missing await * use predefined FormSubmissionData type * add .trim() to sms message * pass contextData instead * finish base setup * add missing trigger in update-workflow.input.ts * allow cal.ai action for form triggers in handler * chore: add support for form workflows on api v2 * fixup! chore: add support for form workflows on api v2 * ai phone call on form submissions (WIP) * use existing type for Option array * pass chosen event type id * refactor: rename * Update apps/web/public/static/locales/en/common.json * Update apps/web/public/static/locales/en/common.json * add missing imports * chore: update set value * fix: remove index * fix: type error * fix: update tetss * use only repository functions in update handler * move all prisma queries from list.handler * review suggestions * fix: use logger * chore: handle workflows api v2 * chore: handle workflows api v2, split in 2 endpoints * fix workflow step creation * remove connect agent and fixes types * add type to workflow * chore: use workflow type in apiv2 WorkflowsOutputService * update worklfow type on update * chore: use workflow type in apiv2 WorkflowsOutputService * fix template body for torm trigger * some UI fixes for email subject/body * resetting email body when changing form triggers * use type field to query workflows * clean up all old active on values * remove responseId from all funciton calls * remove undefined from updateTemplate * refactor: don't use static * fix: type * refactor: split routing form and event-type workflows code * refactor: split routing form and event-type workflows code * fix template text when adding action * chore: don't rename WorkflowActivationDto to avoid ci blocking * refine update schedule to use only allowed actions * fix type error * don't allow whatsapp action with form trigger * fix type error * return early if activeOn array is empty * fix: from step type in BaseFormWorkflowStepDto * fixup! fix: from step type in BaseFormWorkflowStepDto * api v2 updates * move all prisma calls to repository (service/workflows.ts) * use FORM_TRIGGER_WORKFLOW_EVENTS for form queries * use userRepository * use FORM_TRIGGER_WORKFLOW_EVENTS in isFormTrigger * code clean up * code clean up * use repository functions in formSubmissionValidation.ts * fix: schema * refactor: * remove action check in update handler * add event type selection * event type selector improvements * adjust update.handler * set outboundEventTypeId * add back trpc import * fix agent repository functions * clean up * fix bugs caused by merge * pass eventTypeId to updateToolsFromAgentId * add migration for outboundEventTypeId * add SMS actions to allowed form action constants * add cal ai to allowed form actions * pick correct event type for web call * pass correct routed event type id * remove unsued import * fixes for offset api v2 * add missing responseId * fix failing test * fix failing test * improve error message * remove unused imports * chore: handle sms step action for form worklfow in dtos * fix typo * missing missing newStep * minor fixes * remove changes * add routedEventTypeId * fix type error * fix type error * fix typ error in executAPIPhoneCall.tsx * add back inboundEventTypeId * remove console.log * remove outdated code * small fixes * don't throw error for missing phone number * add back filtered triggerOptions * fix eventTypeId in testCall handler * fix type error * update migration * fix trigger is not defined * convert eventTypeId to string * only use outboundEventTypeId for FORM_SUBMITTED trigger * show toast when no event type selected * fix type errors * add missing translation * fix type error * remove callType * fix tests * small fixes * clean up AgentConfigurationSheet * remove EventTypeSelector file * code clean up * clean up * clean up * use resusable function for TestPhoneCallDialog and WebCallDialog * rename result * fix types for event type id * use repository runction in workflowReminder.ts * fix type error * pass eventTypeIds correctly * fix typo * Update apps/web/public/static/locales/en/common.json Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> * use watch instead of getValues * change to z.record(z.unknown()) instead of any() * fix type of eventTypeId * check permissinon for outBoundEventTypeId * add isNaN check * improve function name * update tools when outbound agent event type id changes * pass missing outboundEventTypeId * update migration * fix test * remove cal-ai step from test --------- Co-authored-by: CarinaWolli <wollencarina@gmail.com> Co-authored-by: Udit Takkar <udit222001@gmail.com> Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> Co-authored-by: Benny Joo <sldisek783@gmail.com> Co-authored-by: cal.com <morgan@cal.com> Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Tasker
Tasker: "One who performs a task, as a day-laborer."
Task: "A function to be performed; an objective."
What is it?
Introduces a new pattern called Tasker which may be switched out in the future for other third party services.
Also introduces a base InternalTasker which doesn't require third party dependencies and should work out of the box (by configuring a proper cron).
Why is this needed?
The Tasker pattern is needed to streamline the execution of non-critical tasks in an application, providing a structured approach to task scheduling, execution, retrying, and cancellation. Here's why it's necessary:
-
Offloading non-critical tasks: There are tasks that don't need to be executed immediately on the main thread, such as sending emails, generating reports, or performing periodic maintenance tasks. Offloading these tasks to a separate queue or thread improves the responsiveness and efficiency of the main application.
-
Retry mechanism: Not all tasks succeed on the first attempt due to errors or external dependencies. This pattern incorporates a retry mechanism, which allows failed tasks to be retried automatically for a specified number of attempts. This improves the robustness of the system by handling temporary failures gracefully.
-
Scheduled task execution: Some tasks need to be executed at a specific time or after a certain delay. The Tasker pattern facilitates scheduling tasks for future execution, ensuring they are performed at the designated time without manual intervention.
-
Task cancellation: Occasionally, it's necessary to cancel a scheduled task due to changing requirements or user actions. The Tasker pattern supports task cancellation, enabling previously scheduled tasks to be revoked or removed from the queue before execution.
-
Flexible implementation: The Tasker pattern allows for flexibility in implementation by providing a base structure (
InternalTasker) that can be extended or replaced with third-party services (TriggerDevTasker,AwsSqsTasker, etc.). This modularity ensures that the task execution mechanism can be adapted to suit different application requirements or environments.
Overall, the Tasker pattern enhances the reliability, performance, and maintainability by managing non-critical tasks in a systematic and efficient manner. It abstracts away the complexities of task execution, allowing developers to focus on core application logic while ensuring timely and reliable execution of background tasks.
How does it work?
Since the Tasker is a pattern on itself, it will depend on the actual implementation. For example, a TriggerDevTasker will work very differently from an AwsSqsTasker.
For simplicity sake will explain how the InternalTasker works:
-
Instead of running a non-critical task you schedule using the tasker:
const examplePayload = { example: "payload" }; - await sendWebhook(examplePayload); + await tasker.create("sendWebhook", JSON.stringify(examplePayload)); -
This will create a new task to be run on the next processing of the task queue.
-
Then on the next cron run it will be picked up and executed:
// /app/api/tasks/cron/route.ts import { TaskProcessor } from "@calcom/features/tasker/task-processor"; export async function GET() { // authenticate the call... const processor = new TaskProcessor(); await processor.processQueue(); return Response.json({ success: true }); } -
By default, the cron will run each minute and will pick the next 100 tasks to be executed.
-
If the tasks succeeds, it will be marked as
suceededAt: new Date(). If if fails, theattemptsprop will increase by 1 and will be retried on the next cron run. -
If
attemptsreachesmaxAttemps, it will be considered a failed and won't be retried again. -
By default, tasks will be attempted up to 3 times. This can be overridden when creating a task.
-
From here we can either keep a record of executed tasks, or we can setup another cron to cleanup all successful and failed tasks:
// /app/api/tasks/cleanup/route.ts import { TaskProcessor } from "@calcom/features/tasker/task-processor"; export async function GET() { // authenticate the call... const processor = new TaskProcessor(); await processor.cleanup(); return Response.json({ success: true }); } -
This will delete all failed and successful tasks.
-
A task is just a simple function receives a payload:
type TaskHandler = (payload: string) => Promise<void>;
How to contribute?
You can contribute by either expanding the InternalTasker or creating new Taskers. To see how to add new Taskers, see the tasker-factory.ts file.
You can also take some inspiration by looking into previous attempts to add various Message Queue pull requests: