Skip to content

Conversation

@Udit-takkar
Copy link
Contributor

@Udit-takkar Udit-takkar commented Sep 1, 2025

What does this PR do?

This PR add functionality to create agent when autoCreateAgent is passed for this PR https://github.com/calcom/website/pull/985

Screen.Recording.2025-09-09.at.11.07.54.PM.mov

https://calendso.slack.com/archives/C099U1FRC6T/p1756464036204329?thread_ts=1756463729.787299&cid=C099U1FRC6T

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • N/A I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. If N/A, write N/A here and check the checkbox.
  • N/A I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 1, 2025

Walkthrough

Adds a new Cal AI Phone workflow templates module exporting calAIPhoneWorkflowTemplates with workflows wf-10 and wf-11 (each exposing generalPrompt). Extends the AI voice agent creation schema and handler to accept an optional templateWorkflowId and prefer template-derived generalPrompt when provided. Updates WorkflowStepContainer to support URL-driven auto agent creation using autoCreateAgent and templateWorkflowId, and to accept an optional onSaveWorkflow prop. Propagates a new dynamic variable NUMBER_TO_CALL into prompt templates and the RetellAI call flows (CallService and executeAIPhoneCall).

Possibly related PRs

  • feat: Cal.ai Self Serve #2  #22995: Implements related Cal.ai voice-agent features—workflow/prompt templates, aiVoiceAgent create handler/schema, tasker/Retell provider integrations, and URL-driven agent creation—showing strong code-level overlap.

Pre-merge checks (3 passed)

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title “feat: support auto create agent” directly reflects the core change introduced in this PR—adding support for automatically creating an agent when the autoCreateAgent flag is passed—using concise and clear wording without extraneous details.
Description Check ✅ Passed The description clearly explains that the PR adds functionality to create an agent when autoCreateAgent is provided and links to the related website PR and discussion for context, demonstrating relevance to the changeset.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/auto-create-agent

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@keithwillcode keithwillcode added core area: core, team members only enterprise area: enterprise, audit log, organisation, SAML, SSO labels Sep 1, 2025
@vercel
Copy link

vercel bot commented Sep 9, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
cal Ignored Ignored Sep 10, 2025 8:17am
cal-eu Ignored Ignored Sep 10, 2025 8:17am

@pull-request-size pull-request-size bot added size/L and removed size/M labels Sep 9, 2025
@Udit-takkar Udit-takkar marked this pull request as ready for review September 9, 2025 17:42
@graphite-app graphite-app bot requested a review from a team September 9, 2025 17:42
@dosubot dosubot bot added ai area: AI, cal.ai ✨ feature New feature or request labels Sep 9, 2025
@Udit-takkar Udit-takkar added the High priority Created by Linear-GitHub Sync label Sep 9, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/features/ee/workflows/components/WorkflowStepContainer.tsx (2)

381-383: Wrong toast variant on failed phone verification

Shows “wrong code” with a success toast. Use error when isVerified is false.

Apply this diff:

-    onSuccess: async (isVerified) => {
-      showToast(isVerified ? t("verified_successfully") : t("wrong_code"), "success");
+    onSuccess: async (isVerified) => {
+      showToast(isVerified ? t("verified_successfully") : t("wrong_code"), isVerified ? "success" : "error");

415-421: Email verification: wrong toast variant and state bug

  • Uses success variant for “wrong_code”.
  • setEmailVerified(true) even when verification fails.

Apply this diff:

-    onSuccess: (isVerified) => {
-      showToast(isVerified ? t("verified_successfully") : t("wrong_code"), "success");
-      setEmailVerified(true);
+    onSuccess: (isVerified) => {
+      showToast(isVerified ? t("verified_successfully") : t("wrong_code"), isVerified ? "success" : "error");
+      setEmailVerified(isVerified);
🧹 Nitpick comments (13)
packages/trpc/server/routers/viewer/aiVoiceAgent/create.schema.ts (1)

5-6: Harden numeric fields.

teamId and workflowStepId should be integers > 0 to avoid accidental floats/negatives from query strings.

packages/features/calAIPhone/workflowTemplates.ts (2)

36-39: Tighten availability instructions.

Small clarity tweaks to avoid the model reading out slot-by-slot details.

-      - if availability exists, inform user about the availability range (do not repeat the detailed available slot) and ask user to choose from it. Make sure user chose a slot within detailed available slot.
+      - if availability exists, summarize the availability window (do not enumerate individual slots) and ask the user to pick a time within that window.

20-24: Export a typed ID union and freeze the map for safer downstream usage.

This enables schema/type safety without casts elsewhere.

-export const calAIPhoneWorkflowTemplates = {
+export const calAIPhoneWorkflowTemplates = {
   ...
-};
+} as const;
+
+export type TemplateWorkflowId = keyof typeof calAIPhoneWorkflowTemplates;
packages/trpc/server/routers/viewer/aiVoiceAgent/create.handler.ts (2)

16-16: Destructure is fine; consider naming retellConfig fields for clarity.

Not required, but improves readability when passing through.


20-23: Prefer typed key access and simpler fallback once schema validates IDs.

After constraining templateWorkflowId, you can drop casts/optional chaining.

-  const generalPrompt = templateWorkflowId
-    ? calAIPhoneWorkflowTemplates?.[templateWorkflowId as keyof typeof calAIPhoneWorkflowTemplates]
-        ?.generalPrompt
-    : undefined;
+  const generalPrompt =
+    templateWorkflowId
+      ? calAIPhoneWorkflowTemplates[templateWorkflowId].generalPrompt
+      : undefined;
packages/features/ee/workflows/components/WorkflowStepContainer.tsx (8)

131-133: Safer searchParams dependency handling

useSearchParams returns a new object on URL changes. Use its serialized value in effects to avoid unnecessary re-runs due to object identity.

Apply this diff in the effect dependency array (see also lines 292-302):

-    searchParams,
+    searchParams?.toString(),

292-302: Effect dependencies: avoid mutation objects and prefer primitive deps

createAgentMutation is an object whose identity can change; it shouldn’t be in deps. Prefer primitives and stable functions.

Apply this diff:

-    searchParams,
+    searchParams?.toString(),
     autoAgentCreationAttempted,
     step,
     stepAgentId,
     teamId,
     onSaveWorkflow,
-    createAgentMutation,
     form,
     t,
     router,

745-747: Disable “Set up” when onSaveWorkflow is absent

Prevents a silent no-op click if the callback isn’t provided.

Apply this diff:

-                    <Button
+                    <Button
                       color="secondary"
+                      disabled={!onSaveWorkflow}
                       onClick={async () => {
                         // save the workflow first to get the step id
                         if (onSaveWorkflow) {

903-907: Localize placeholder text

Replace hardcoded “Verification code” with t().

Apply this diff:

-                          <TextField
+                          <TextField
                             className="h-[36px] rounded-r-none border-r-transparent"
-                            placeholder="Verification code"
+                            placeholder={t("verification_code")}

1058-1064: Localize placeholder text (duplicate spot)

Same fix for the email verification input.

Apply this diff:

-                          <TextField
+                          <TextField
                             className="h-[36px] rounded-r-none border-r-transparent"
-                            placeholder="Verification code"
+                            placeholder={t("verification_code")}

127-127: Prefer named export over default export

Project guideline favors named exports for better tree-shaking and refactors.

Apply this diff:

-export default function WorkflowStepContainer(props: WorkflowStepProps) {
+export function WorkflowStepContainer(props: WorkflowStepProps) {

Follow up: update imports at call sites to import { WorkflowStepContainer } from "...";.


245-291: Optional: use mutateAsync for sequential flow and error handling

Using mutateAsync lets you await creation and branch on success/failure without relying on onSuccess callbacks, improving readability.

Example within this block:

-            createAgentMutation.mutate({
+            await createAgentMutation.mutateAsync({
               teamId,
               workflowStepId: updatedStep.id,
               templateWorkflowId,
             });
-            const url = new URL(window.location.href);
+            const url = new URL(window.location.href);
             url.searchParams.delete("autoCreateAgent");
             url.searchParams.delete("templateWorkflowId");
             router.replace(url.pathname + url.search);

554-557: Clarify canRequirePhoneNumber naming

The helper returns true for attendee actions only; consider a name like requiresRecipientNumber to better reflect intent. Optional.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ad4cf0c and 295d64a.

📒 Files selected for processing (4)
  • packages/features/calAIPhone/workflowTemplates.ts (1 hunks)
  • packages/features/ee/workflows/components/WorkflowStepContainer.tsx (4 hunks)
  • packages/trpc/server/routers/viewer/aiVoiceAgent/create.handler.ts (2 hunks)
  • packages/trpc/server/routers/viewer/aiVoiceAgent/create.schema.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Always use t() for text localization in frontend code; direct text embedding should trigger a warning

Files:

  • packages/features/ee/workflows/components/WorkflowStepContainer.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/features/ee/workflows/components/WorkflowStepContainer.tsx
  • packages/trpc/server/routers/viewer/aiVoiceAgent/create.handler.ts
  • packages/features/calAIPhone/workflowTemplates.ts
  • packages/trpc/server/routers/viewer/aiVoiceAgent/create.schema.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • packages/features/ee/workflows/components/WorkflowStepContainer.tsx
  • packages/trpc/server/routers/viewer/aiVoiceAgent/create.handler.ts
  • packages/features/calAIPhone/workflowTemplates.ts
  • packages/trpc/server/routers/viewer/aiVoiceAgent/create.schema.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/trpc/server/routers/viewer/aiVoiceAgent/create.handler.ts
  • packages/features/calAIPhone/workflowTemplates.ts
  • packages/trpc/server/routers/viewer/aiVoiceAgent/create.schema.ts
🧠 Learnings (7)
📓 Common learnings
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/features/ee/workflows/lib/schema.ts:41-43
Timestamp: 2025-08-14T10:30:23.062Z
Learning: In calcom/cal.com workflows with CAL_AI_PHONE_CALL actions, agentId can legitimately be null during initial setup. The workflow is: 1) save workflow to get step ID, 2) use step ID to create and link agent. Therefore, agentId should remain nullable in schemas to support this multi-step setup process (per maintainer Udit-takkar).
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/features/ee/workflows/lib/reminders/aiPhoneCallManager.ts:167-193
Timestamp: 2025-08-19T08:45:41.834Z
Learning: In calcom/cal.com AI phone call scheduling (aiPhoneCallManager.ts), workflow reminder records are intentionally kept in the database even when task scheduling fails, as they provide valuable debugging information for troubleshooting scheduling issues, per maintainer Udit-takkar in PR #22995.
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/features/ee/workflows/components/AgentConfigurationSheet.tsx:348-371
Timestamp: 2025-08-15T00:27:33.280Z
Learning: In calcom/cal.com workflows and AI agent components, variable insertion follows a consistent pattern of directly transforming the input variable with toUpperCase() and replace(/ /g, "_") to create tokens like {VARIABLE_NAME}. The AgentConfigurationSheet.tsx implementation correctly follows this same pattern as WorkflowStepContainer.tsx, per maintainer Udit-takkar in PR #22995.
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/trpc/server/routers/viewer/workflows/update.handler.ts:738-763
Timestamp: 2025-08-15T00:07:30.058Z
Learning: In calcom/cal.com workflows, Cal AI phone call actions (CAL_AI_PHONE_CALL) intentionally always require the phone number field when the action is present, unlike SMS/WhatsApp actions which respect the step.numberRequired flag. This is the intended behavior per maintainer Udit-takkar in PR #22995.
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/features/ee/workflows/components/WorkflowStepContainer.tsx:641-649
Timestamp: 2025-08-26T20:09:17.089Z
Learning: In packages/features/ee/workflows/components/WorkflowStepContainer.tsx, Cal.AI actions are intentionally filtered out/hidden for organization workflows when props.isOrganization is true. This restriction is by design per maintainer Udit-takkar in PR #22995, despite the broader goal of enabling Cal.AI self-serve.
📚 Learning: 2025-08-26T20:09:17.089Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/features/ee/workflows/components/WorkflowStepContainer.tsx:641-649
Timestamp: 2025-08-26T20:09:17.089Z
Learning: In packages/features/ee/workflows/components/WorkflowStepContainer.tsx, Cal.AI actions are intentionally filtered out/hidden for organization workflows when props.isOrganization is true. This restriction is by design per maintainer Udit-takkar in PR #22995, despite the broader goal of enabling Cal.AI self-serve.

Applied to files:

  • packages/features/ee/workflows/components/WorkflowStepContainer.tsx
  • packages/features/calAIPhone/workflowTemplates.ts
📚 Learning: 2025-08-15T00:27:33.280Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/features/ee/workflows/components/AgentConfigurationSheet.tsx:348-371
Timestamp: 2025-08-15T00:27:33.280Z
Learning: In calcom/cal.com workflows and AI agent components, variable insertion follows a consistent pattern of directly transforming the input variable with toUpperCase() and replace(/ /g, "_") to create tokens like {VARIABLE_NAME}. The AgentConfigurationSheet.tsx implementation correctly follows this same pattern as WorkflowStepContainer.tsx, per maintainer Udit-takkar in PR #22995.

Applied to files:

  • packages/features/ee/workflows/components/WorkflowStepContainer.tsx
📚 Learning: 2025-08-14T10:48:52.586Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/trpc/server/routers/viewer/ai/_router.ts:46-84
Timestamp: 2025-08-14T10:48:52.586Z
Learning: In calcom/cal.com PR #22995, packages/trpc/server/routers/viewer/ai/_router.ts, the voiceId input parameter in the create endpoint is intentionally not forwarded to aiService.createAgent() as voice customization is not required at the moment (per maintainer Udit-takkar). Future reviews should not flag this as missing functionality unless requirements change.

Applied to files:

  • packages/trpc/server/routers/viewer/aiVoiceAgent/create.handler.ts
  • packages/trpc/server/routers/viewer/aiVoiceAgent/create.schema.ts
📚 Learning: 2025-08-17T22:00:16.329Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/trpc/server/routers/viewer/aiVoiceAgent/_router.ts:117-126
Timestamp: 2025-08-17T22:00:16.329Z
Learning: In calcom/cal.com PR #22995, packages/trpc/server/routers/viewer/aiVoiceAgent/_router.ts, the enabled input parameter in the update endpoint is intentionally not forwarded to aiService.updateAgentConfiguration() as the enabled/disabled agent functionality is not required at the moment (per maintainer Udit-takkar). Future reviews should not flag this as missing functionality unless requirements change.

Applied to files:

  • packages/trpc/server/routers/viewer/aiVoiceAgent/create.handler.ts
  • packages/trpc/server/routers/viewer/aiVoiceAgent/create.schema.ts
📚 Learning: 2025-08-26T20:22:47.013Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/features/calAIPhone/providers/retellAI/services/AgentService.ts:83-88
Timestamp: 2025-08-26T20:22:47.013Z
Learning: In calcom/cal.com, the executeAIPhoneCall task in packages/features/tasker/tasks/executeAIPhoneCall.ts is executed internally by the workflow system and not accessible externally, so RBAC checks on eventTypeId within this internal execution path are not required for security (per maintainer Udit-takkar in PR #22995).

Applied to files:

  • packages/trpc/server/routers/viewer/aiVoiceAgent/create.handler.ts
📚 Learning: 2025-08-19T08:45:41.834Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/features/ee/workflows/lib/reminders/aiPhoneCallManager.ts:167-193
Timestamp: 2025-08-19T08:45:41.834Z
Learning: In calcom/cal.com AI phone call scheduling (aiPhoneCallManager.ts), workflow reminder records are intentionally kept in the database even when task scheduling fails, as they provide valuable debugging information for troubleshooting scheduling issues, per maintainer Udit-takkar in PR #22995.

Applied to files:

  • packages/features/calAIPhone/workflowTemplates.ts
🧬 Code graph analysis (1)
packages/trpc/server/routers/viewer/aiVoiceAgent/create.handler.ts (1)
packages/features/calAIPhone/workflowTemplates.ts (1)
  • calAIPhoneWorkflowTemplates (20-92)
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Install dependencies / Yarn install & cache
🔇 Additional comments (9)
packages/trpc/server/routers/viewer/aiVoiceAgent/create.schema.ts (1)

22-23: Voice ID presence is fine.

Reminder: not forwarded by design per prior decision; no change requested.

packages/features/calAIPhone/workflowTemplates.ts (1)

59-61: Policy check: “only schedule in current calendar year.”

Is this intentional for reminder/reschedule flows in late December? Might block early January reschedules. Confirm product intent.

packages/trpc/server/routers/viewer/aiVoiceAgent/create.handler.ts (1)

25-34: LGTM on precedence: template prompt overrides input prompt.

Good default; once schema rejects unknown IDs, behavior is deterministic.

packages/features/ee/workflows/components/WorkflowStepContainer.tsx (6)

3-3: Confirm App Router usage for next/navigation hooks

Using useParams/useRouter/useSearchParams requires a Client Component in the App Router. Ensure this file has "use client" and isn’t consumed from Pages Router (which would need next/router).


81-82: Prop API extension looks good

Adding optional onSaveWorkflow aligns with the new flow. Verify all call sites pass it where needed to avoid no-op buttons.


134-134: Destructuring update is fine

Pulling onSaveWorkflow from props here is correct and used consistently below.


243-243: Good guard to prevent repeated auto-creation

autoAgentCreationAttempted prevents loops. Nice.


708-721: Action filtering respects org constraints

Hiding Cal.AI actions when isOrganization is true matches prior intent. LGTM.


127-160: Verify CAL_AI recipient number UX vs backend contract

Earlier backend behavior required a recipient phone for CAL_AI steps irrespective of numberRequired. This UI hides the sendTo input for CAL_AI. Confirm the server-side validation accepts this (e.g., if the number is sourced elsewhere) to avoid save errors.

Comment on lines +16 to +18
const scheduleRule = ` ## Schedule Rule
Current time is {{current_time}}. You only schedule time in current calendar year, you cannot schedule time that'''s in the past.`;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix stray triple quotes in “that'''s”.

User-facing grammar.

-  Current time is {{current_time}}. You only schedule time in current calendar year, you cannot schedule time that'''s in the past.`;
+  Current time is {{current_time}}. You only schedule time in the current calendar year; you cannot schedule time that's in the past.`;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const scheduleRule = ` ## Schedule Rule
Current time is {{current_time}}. You only schedule time in current calendar year, you cannot schedule time that'''s in the past.`;
const scheduleRule = ` ## Schedule Rule
Current time is {{current_time}}. You only schedule time in the current calendar year; you cannot schedule time that's in the past.`;
🤖 Prompt for AI Agents
In packages/features/calAIPhone/workflowTemplates.ts around lines 16 to 18, fix
the stray triple quotes in the string: replace "that'''s" with the correct
contraction "that's" (or "that is" if preferred) so the user-facing text reads
properly (e.g., "you cannot schedule time that's in the past."); ensure the
surrounding spacing and punctuation remain valid in the template string.

Comment on lines +249 to +258
if (
autoCreateAgent === "true" &&
!autoAgentCreationAttempted &&
templateWorkflowId &&
step &&
step.action === WorkflowActions.CAL_AI_PHONE_CALL &&
!stepAgentId &&
step.id &&
onSaveWorkflow
) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Remove step.id from the auto-create guard (blocks intended first-run path)

Requiring step.id defeats the purpose of calling onSaveWorkflow to obtain the step ID, so the flow won’t run on brand-new steps. Drop that check.

Apply this diff:

-      step &&
-      step.action === WorkflowActions.CAL_AI_PHONE_CALL &&
-      !stepAgentId &&
-      step.id &&
-      onSaveWorkflow
+      step &&
+      step.action === WorkflowActions.CAL_AI_PHONE_CALL &&
+      !stepAgentId &&
+      onSaveWorkflow

Optionally also gate on readOnly to avoid unexpected mutations in view-only contexts.


🏁 Script executed:

#!/bin/bash
# Find the WorkflowStepContainer.tsx file path
FILE=$(fd WorkflowStepContainer.tsx)
echo "Using file: $FILE"

echo "\n--- Snippet from lines 240-300 ---"
sed -n '240,300p' "$FILE"

echo "\n--- onSaveWorkflow references ---"
rg -n 'onSaveWorkflow' -C2 "$FILE"

Length of output: 3030


Remove step.id from the auto-create guard

Requiring step.id blocks the intended first-run path since new steps lack an ID until onSaveWorkflow completes; drop step.id from the condition.

-      step &&
-      step.action === WorkflowActions.CAL_AI_PHONE_CALL &&
-      !stepAgentId &&
-      step.id &&
-      onSaveWorkflow
+      step &&
+      step.action === WorkflowActions.CAL_AI_PHONE_CALL &&
+      !stepAgentId &&
+      onSaveWorkflow

Consider also adding !readOnly to prevent unintended mutations in view-only mode.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (
autoCreateAgent === "true" &&
!autoAgentCreationAttempted &&
templateWorkflowId &&
step &&
step.action === WorkflowActions.CAL_AI_PHONE_CALL &&
!stepAgentId &&
step.id &&
onSaveWorkflow
) {
if (
autoCreateAgent === "true" &&
!autoAgentCreationAttempted &&
templateWorkflowId &&
step &&
step.action === WorkflowActions.CAL_AI_PHONE_CALL &&
!stepAgentId &&
onSaveWorkflow
) {
🤖 Prompt for AI Agents
In packages/features/ee/workflows/components/WorkflowStepContainer.tsx around
lines 249 to 258, the auto-create guard currently requires step.id which
prevents auto-creation on new steps (they have no id yet); remove the step.id
check from the if condition and also add a !readOnly check to the conjunction so
auto-agent creation only runs when not in view-only mode.

name: z.string().optional(),
teamId: z.number().optional(),
workflowStepId: z.number().optional(),
templateWorkflowId: z.string().optional(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Validate templateWorkflowId against known template keys (reject unknown IDs).

Right now any string is accepted and silently ignored in the handler. Constrain it to the supported keys to fail fast and avoid confusing fallbacks.

Apply:

+import { calAIPhoneWorkflowTemplates } from "@calcom/features/calAIPhone/workflowTemplates";
 
 export const ZCreateInputSchema = z.object({
   name: z.string().optional(),
-  teamId: z.number().optional(),
-  workflowStepId: z.number().optional(),
-  templateWorkflowId: z.string().optional(),
+  teamId: z.number().int().positive().optional(),
+  workflowStepId: z.number().int().positive().optional(),
+  templateWorkflowId: z
+    .string()
+    .optional()
+    .refine(
+      (v) => !v || v in calAIPhoneWorkflowTemplates,
+      "Invalid templateWorkflowId"
+    ),
   generalPrompt: z.string().optional(),
   beginMessage: z.string().optional(),
   ...
 });
 
+// Optionally enforce mutual exclusivity to avoid ambiguity
+export const ZCreateInputSchemaExclusive = ZCreateInputSchema.refine(
+  (d) => !(d.templateWorkflowId && d.generalPrompt),
+  { message: "Provide either templateWorkflowId or generalPrompt, not both.", path: ["templateWorkflowId"] }
+);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
templateWorkflowId: z.string().optional(),
// packages/trpc/server/routers/viewer/aiVoiceAgent/create.schema.ts
import { z } from "zod";
import { calAIPhoneWorkflowTemplates } from "@calcom/features/calAIPhone/workflowTemplates";
export const ZCreateInputSchema = z.object({
name: z.string().optional(),
- teamId: z.number().optional(),
- workflowStepId: z.number().optional(),
teamId: z.number().int().positive().optional(),
workflowStepId: z.number().int().positive().optional(),
templateWorkflowId: z
.string()
.optional()
.refine(
(v) => !v || v in calAIPhoneWorkflowTemplates,
"Invalid templateWorkflowId"
),
generalPrompt: z.string().optional(),
beginMessage: z.string().optional(),
// … other fields …
});
// Optionally enforce mutual exclusivity to avoid ambiguity
export const ZCreateInputSchemaExclusive = ZCreateInputSchema.refine(
(d) => !(d.templateWorkflowId && d.generalPrompt),
{
message: "Provide either templateWorkflowId or generalPrompt, not both.",
path: ["templateWorkflowId"],
}
);

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (11)
packages/features/tasker/tasks/executeAIPhoneCall.ts (4)

151-156: Clarify error message for missing toNumber

The log/error imply attendee lookup, but the source is payload.toNumber. Recommend tightening the message.

Apply this diff:

-  if (!numberToCall) {
-    log.warn(`No phone number found for attendee in booking ${booking.uid}`);
-    throw new Error("No phone number found for attendee");
-  }
+  if (!numberToCall) {
+    log.warn(`No 'toNumber' provided in AI phone call payload for booking ${booking.uid}`);
+    throw new Error("Missing 'toNumber' in AI phone call payload");
+  }

212-217: Use the computed timeZone consistently

Defaulting to "Europe/London" diverges from the earlier resolved timeZone and can mis-route tools. Use the resolved timeZone.

Apply this diff:

-    await aiService.updateToolsFromAgentId(data.providerAgentId, {
-      eventTypeId: booking.eventTypeId,
-      timeZone: attendee?.timeZone ?? "Europe/London",
-      userId: data.userId,
-      teamId: data.teamId,
-    });
+    await aiService.updateToolsFromAgentId(data.providerAgentId, {
+      eventTypeId: booking.eventTypeId,
+      timeZone,
+      userId: data.userId,
+      teamId: data.teamId,
+    });

225-242: Reduce PII in logs

Avoid logging full provider response and raw phone numbers at info level.

Apply this diff:

-    log.info("AI phone call created successfully:", call);
+    log.info("AI phone call created successfully", { callId: call.call_id, status: call.call_status });
...
-    log.info(`AI phone call executed successfully for workflow reminder ${data.workflowReminderId}`, {
+    log.info(`AI phone call executed successfully for workflow reminder ${data.workflowReminderId}`, {
       callId: call.call_id,
       agentId: data.agentId,
       fromNumber: data.fromNumber,
-      toNumber: numberToCall,
+      toNumber: `***${numberToCall.slice(-4)}`,
       bookingUid: data.bookingUid,
     });

151-156: Leverage existing phone utilities to normalize/validate toNumber
Import and use the formatPhoneNumber helper (packages/lib/formatPhoneNumber.ts) to normalize into international format, and guard against invalid values with isValidPhoneNumber (from libphonenumber-js) before proceeding. This reduces downstream provider errors without adding new dependencies.

packages/features/calAIPhone/providers/retellAI/services/CallService.ts (3)

51-59: Default-inject NUMBER_TO_CALL at call creation

Ensures templates resolve the phone number even if callers forget to include it in dynamicVariables.

Apply this diff:

     const { fromNumber, toNumber, dynamicVariables } = data;
 
     try {
+      const finalDynamicVariables = dynamicVariables
+        ? ({ NUMBER_TO_CALL: toNumber, ...dynamicVariables } as RetellDynamicVariables)
+        : ({ NUMBER_TO_CALL: toNumber } as RetellDynamicVariables);
       return await this.retellRepository.createPhoneCall({
         fromNumber,
         toNumber,
-        dynamicVariables,
+        dynamicVariables: finalDynamicVariables,
       });

138-160: Make test-call timestamps reflect 'now'

Static dates can conflict with scheduling guardrails in prompts. Suggest deriving from timeZone.

Apply this diff:

+    // derive friendly date/time for the test call in the provided timeZone
+    const now = new Date();
+    const dateStr = now.toLocaleDateString("en-US", {
+      weekday: "long",
+      month: "long",
+      day: "numeric",
+      year: "numeric",
+      timeZone,
+    });
+    const startStr = now.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit", timeZone });
+    const endStr = new Date(now.getTime() + 30 * 60 * 1000).toLocaleTimeString("en-US", {
+      hour: "numeric",
+      minute: "2-digit",
+      timeZone,
+    });
...
       dynamicVariables: {
         EVENT_NAME: "Test Call with Agent",
-        EVENT_DATE: "Monday, January 15, 2025",
-        EVENT_TIME: "2:00 PM",
-        EVENT_END_TIME: "2:30 PM",
+        EVENT_DATE: dateStr,
+        EVENT_TIME: startStr,
+        EVENT_END_TIME: endStr,
         TIMEZONE: timeZone,
         LOCATION: "Phone Call",

101-107: Validate and normalize toNumber before use
Trim is good; add an E.164 format check and normalization here using the existing libphonenumber-js utilities (e.g. isValidPhoneNumber or parsePhoneNumberWithError from "libphonenumber-js/max" to throw on invalid input and use parsed.number as the normalized value).

packages/features/calAIPhone/promptTemplates.ts (4)

38-38: Typo: “emit” → “omit”

Minor wording fix.

Apply this diff:

-  If you are saying a time like 8:00 AM, just say 8 AM and emit the trailing zeros.
+  If you are saying a time like 8:00 AM, just say 8 AM and omit the trailing zeros.

42-43: Fix stray quotes in “role's”

Clean up triple quotes.

Apply this diff:

-  Stay in Character: Keep conversations within your role'''s scope, guiding them back creatively without repeating.
+  Stay in Character: Keep conversations within your role's scope, guiding them back creatively without repeating.

46-46: Fix stray quotes in “that's”

Minor punctuation cleanup.

Apply this diff:

-  Current time is {{current_time}}. You only schedule time in current calendar year, you cannot schedule time that'''s in the past.
+  Current time is {{current_time}}. You only schedule time in the current calendar year; you cannot schedule time that's in the past.

50-51: Clarify step 2 wording

“not unknown” is confusing; prefer “known,” and tighten the instruction.

Apply this diff:

-  2. If {{ATTENDEE_EMAIL}} is not unknown then Use name {{ATTENDEE_NAME}} and email {{ATTENDEE_EMAIL}} for creating booking else Ask for user name and email and Confirm the name and email with user by reading it back to user.
+  2. If {{ATTENDEE_EMAIL}} is known, use name {{ATTENDEE_NAME}} and email {{ATTENDEE_EMAIL}} to create the booking; otherwise, ask for the user's name and email and read them back to confirm.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 295d64a and 34160b8.

📒 Files selected for processing (4)
  • packages/features/calAIPhone/promptTemplates.ts (1 hunks)
  • packages/features/calAIPhone/providers/retellAI/services/CallService.ts (1 hunks)
  • packages/features/calAIPhone/workflowTemplates.ts (1 hunks)
  • packages/features/tasker/tasks/executeAIPhoneCall.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/features/calAIPhone/workflowTemplates.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*Service.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Service files must include Service suffix, use PascalCase matching exported class, and avoid generic names (e.g., MembershipService.ts)

Files:

  • packages/features/calAIPhone/providers/retellAI/services/CallService.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/features/calAIPhone/providers/retellAI/services/CallService.ts
  • packages/features/tasker/tasks/executeAIPhoneCall.ts
  • packages/features/calAIPhone/promptTemplates.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/features/calAIPhone/providers/retellAI/services/CallService.ts
  • packages/features/tasker/tasks/executeAIPhoneCall.ts
  • packages/features/calAIPhone/promptTemplates.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • packages/features/calAIPhone/providers/retellAI/services/CallService.ts
  • packages/features/tasker/tasks/executeAIPhoneCall.ts
  • packages/features/calAIPhone/promptTemplates.ts
🧠 Learnings (6)
📓 Common learnings
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/features/ee/workflows/lib/schema.ts:41-43
Timestamp: 2025-08-14T10:30:23.062Z
Learning: In calcom/cal.com workflows with CAL_AI_PHONE_CALL actions, agentId can legitimately be null during initial setup. The workflow is: 1) save workflow to get step ID, 2) use step ID to create and link agent. Therefore, agentId should remain nullable in schemas to support this multi-step setup process (per maintainer Udit-takkar).
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/features/ee/workflows/components/AgentConfigurationSheet.tsx:348-371
Timestamp: 2025-08-15T00:27:33.280Z
Learning: In calcom/cal.com workflows and AI agent components, variable insertion follows a consistent pattern of directly transforming the input variable with toUpperCase() and replace(/ /g, "_") to create tokens like {VARIABLE_NAME}. The AgentConfigurationSheet.tsx implementation correctly follows this same pattern as WorkflowStepContainer.tsx, per maintainer Udit-takkar in PR #22995.
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/trpc/server/routers/viewer/workflows/update.handler.ts:738-763
Timestamp: 2025-08-15T00:07:30.058Z
Learning: In calcom/cal.com workflows, Cal AI phone call actions (CAL_AI_PHONE_CALL) intentionally always require the phone number field when the action is present, unlike SMS/WhatsApp actions which respect the step.numberRequired flag. This is the intended behavior per maintainer Udit-takkar in PR #22995.
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/features/ee/workflows/lib/reminders/aiPhoneCallManager.ts:167-193
Timestamp: 2025-08-19T08:45:41.834Z
Learning: In calcom/cal.com AI phone call scheduling (aiPhoneCallManager.ts), workflow reminder records are intentionally kept in the database even when task scheduling fails, as they provide valuable debugging information for troubleshooting scheduling issues, per maintainer Udit-takkar in PR #22995.
📚 Learning: 2025-08-08T10:26:13.362Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22919
File: packages/features/calAIPhone/providers/retellAI/services/PhoneNumberService.ts:212-220
Timestamp: 2025-08-08T10:26:13.362Z
Learning: In calcom/cal.com PR #22919, packages/features/calAIPhone/providers/retellAI/services/PhoneNumberService.ts should include the phone number in client-facing HttpError messages (e.g., in updatePhoneNumber/getPhoneNumber catch blocks). Do not suggest redacting the phone number from these errors unless requirements change (per maintainer: Udit-takkar).

Applied to files:

  • packages/features/calAIPhone/providers/retellAI/services/CallService.ts
  • packages/features/tasker/tasks/executeAIPhoneCall.ts
  • packages/features/calAIPhone/promptTemplates.ts
📚 Learning: 2025-08-15T00:07:30.058Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/trpc/server/routers/viewer/workflows/update.handler.ts:738-763
Timestamp: 2025-08-15T00:07:30.058Z
Learning: In calcom/cal.com workflows, Cal AI phone call actions (CAL_AI_PHONE_CALL) intentionally always require the phone number field when the action is present, unlike SMS/WhatsApp actions which respect the step.numberRequired flag. This is the intended behavior per maintainer Udit-takkar in PR #22995.

Applied to files:

  • packages/features/calAIPhone/providers/retellAI/services/CallService.ts
  • packages/features/tasker/tasks/executeAIPhoneCall.ts
  • packages/features/calAIPhone/promptTemplates.ts
📚 Learning: 2025-08-08T09:27:23.896Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22919
File: packages/features/calAIPhone/providers/retellAI/services/AgentService.ts:195-216
Timestamp: 2025-08-08T09:27:23.896Z
Learning: In PR calcom/cal.com#22919, file packages/features/calAIPhone/providers/retellAI/services/AgentService.ts, the updateAgentConfiguration method intentionally does not persist the optional `name` parameter to the repository for now, per maintainer (Udit-takkar). Future reviews should not flag this unless requirements change.

Applied to files:

  • packages/features/calAIPhone/providers/retellAI/services/CallService.ts
📚 Learning: 2025-08-26T20:22:47.013Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/features/calAIPhone/providers/retellAI/services/AgentService.ts:83-88
Timestamp: 2025-08-26T20:22:47.013Z
Learning: In calcom/cal.com, the executeAIPhoneCall task in packages/features/tasker/tasks/executeAIPhoneCall.ts is executed internally by the workflow system and not accessible externally, so RBAC checks on eventTypeId within this internal execution path are not required for security (per maintainer Udit-takkar in PR #22995).

Applied to files:

  • packages/features/tasker/tasks/executeAIPhoneCall.ts
📚 Learning: 2025-08-08T09:29:11.681Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22919
File: packages/features/calAIPhone/interfaces/AIPhoneService.interface.ts:118-143
Timestamp: 2025-08-08T09:29:11.681Z
Learning: In calcom/cal.com PR #22919, packages/features/calAIPhone/interfaces/AIPhoneService.interface.ts (TypeScript), the AIPhoneServiceAgentListItem is required to include user.email in listAgents responses (per maintainer Udit-takkar). Future reviews should not flag this as unnecessary PII unless requirements change.

Applied to files:

  • packages/features/tasker/tasks/executeAIPhoneCall.ts
🔇 Additional comments (4)
packages/features/tasker/tasks/executeAIPhoneCall.ts (1)

186-186: Add NUMBER_TO_CALL to dynamicVariables — LGTM

Aligned with prompt updates and templates using {{NUMBER_TO_CALL}}.

packages/features/calAIPhone/providers/retellAI/services/CallService.ts (1)

158-159: Propagating NUMBER_TO_CALL in test calls — LGTM

Keeps prompts consistent between prod calls and test calls.

packages/features/calAIPhone/promptTemplates.ts (2)

56-56: Use {{NUMBER_TO_CALL}} in booking step — LGTM

Matches dynamicVariables addition and workflow templates.


60-60: Add explicit end_call step — LGTM

Clear termination guidance for the agent.

Copy link
Member

@CarinaWolli CarinaWolli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good and works as expected 👍

@CarinaWolli CarinaWolli enabled auto-merge (squash) September 10, 2025 08:19
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (3)
packages/features/calAIPhone/workflowTemplates.ts (3)

13-13: Fix stray triple quotes: role'''s → role's.

User-facing copy.

Apply:

-  Stay in Character: Keep conversations within your role'''s scope, guiding them back creatively without repeating.
+  Stay in Character: Keep conversations within your role's scope, guiding them back creatively without repeating.

16-18: Grammar + stray triple quotes in scheduleRule.

Tighten wording; fix that'''s → that's.

-const scheduleRule = ` ## Schedule Rule
-  Current time is {{current_time}}. You only schedule time in current calendar year, you cannot schedule time that'''s in the past.`;
+const scheduleRule = ` ## Schedule Rule
+  Current time is {{current_time}}. Only schedule times in the current calendar year; you cannot schedule time that's in the past.`;

40-47: Step numbering jumps (3 → 5) and wording polish.

Renumber to keep coherent flow; tighten phrasing.

-  5. If {{ATTENDEE_EMAIL}} is not unknown then Use name {{ATTENDEE_NAME}} and email {{ATTENDEE_EMAIL}} for creating booking else Ask for user name and email and Confirm the name and email with user by reading it back to user.
-  6. Once confirmed, you can use {{NUMBER_TO_CALL}} as phone number for creating booking and call function book_appointment_{{eventTypeId}} to book the appointment.
-    - if booking returned booking detail, it means booking is successful, proceed to step 7.
-    - if booking returned error message, let user know why the booking was not successful, and maybe start over with step 3a.
-  7. If they don't want to reschedule:
+  4. If {{ATTENDEE_EMAIL}} is known, use {{ATTENDEE_NAME}} and {{ATTENDEE_EMAIL}} for booking; otherwise, ask for the user's name and email and confirm by reading them back.
+  5. Once confirmed, use {{NUMBER_TO_CALL}} as the phone number when creating the booking and call function book_appointment_{{eventTypeId}}.
+    - If booking returns details, booking is successful; proceed to step 6.
+    - If booking returns an error, explain why the booking failed and restart at step 3a.
+  6. If they don't want to reschedule:
      - Thank them for their time and let them know they can always reach out if they change their mind.
-  8. Before ending, ask if there's anything else you can help with.
-  9. Thank them for their time and call function end_call to hang up.`,
+  7. Before ending, ask if there's anything else you can help with.
+  8. Thank them for their time and call function end_call to hang up.`,
🧹 Nitpick comments (5)
packages/features/calAIPhone/workflowTemplates.ts (5)

19-19: Comment grammar nit.

-// Key are from components/sections/template/data/workflows.ts page in https://github.com/calcom/website
+// Keys are taken from components/sections/template/data/workflows.ts in https://github.com/calcom/website

63-63: Time phrasing may drift from reality.

If calls can be offset by queue/scheduling, consider removing “That’s in about an hour.”

-  2. Provide the meeting details: "Your appointment is scheduled for today at {{EVENT_TIME}} {{TIMEZONE}}. That's in about an hour."
+  2. Provide the meeting details: "Your appointment is scheduled for today at {{EVENT_TIME}} {{TIMEZONE}}."

72-81: Consistency/grammar in reschedule sub-steps.

-       5a. If {{ATTENDEE_EMAIL}} is not unknown: Use name {{ATTENDEE_NAME}} and email {{ATTENDEE_EMAIL}} for creating booking
-       5b. If {{ATTENDEE_EMAIL}} is unknown: Ask for user name and email and confirm by reading it back to user
-       5c. Ask user for "When would you want to reschedule?"
+       5a. If {{ATTENDEE_EMAIL}} is known: use {{ATTENDEE_NAME}} and {{ATTENDEE_EMAIL}} for booking.
+       5b. If {{ATTENDEE_EMAIL}} is unknown: ask for the user's name and email and confirm by reading them back.
+       5c. Ask: "When would you like to reschedule?"
        5d. Call function check_availability_{{eventTypeId}} to check for availability in the user provided time range.
-       5e. If availability exists, inform user about the availability range (do not repeat the detailed available slot) and ask user to choose from it. Make sure user chose a slot within detailed available slot.
-       5f. If availability does not exist, ask user to select another time range for the appointment (repeat step 5c).
-       5g. Confirm the date and time selected by user: "Just to confirm, you want to book the appointment at ..."
-       5h. Once confirmed, you can use {{NUMBER_TO_CALL}} as phone number for creating booking and call function book_appointment_{{eventTypeId}} to book the appointment.
-       5i. If booking returned booking detail, it means booking is successful, proceed to step 7.
-       5j. If booking returned error message, let user know why the booking was not successful, and maybe start over (return to step 5c).
+       5e. If availability exists, share the availability range (do not enumerate every slot) and ask them to choose; ensure the chosen time falls within the provided slots.
+       5f. If availability does not exist, ask them to select another time range (repeat step 5c).
+       5g. Confirm the selected date and time: "Just to confirm, you want to book the appointment at …"
+       5h. Once confirmed, use {{NUMBER_TO_CALL}} as the phone number when creating the booking and call function book_appointment_{{eventTypeId}}.
+       5i. If booking returns details, booking is successful; proceed to step 7.
+       5j. If booking returns an error, explain why the booking failed and restart at step 5c.

86-86: Duration calc requires start and end times.

-       - Duration: Use {{EVENT_END_TIME}} to calculate and state duration
+       - Duration: Use {{EVENT_TIME}} and {{EVENT_END_TIME}} to calculate and state duration

20-92: Preserve literal types for template IDs and shape.

-export const calAIPhoneWorkflowTemplates = {
+export const calAIPhoneWorkflowTemplates = {
   //  name: "Cal AI No-show Follow-up Call",
   // description: "Automatically call attendee when marked as no-show"
   "wf-10": {
     generalPrompt: `## You are calling an attendee who was marked as a no-show for their appointment. Your goal is to help them reschedule. Be understanding, friendly, and non-judgmental.
@@
   "wf-11": {
     generalPrompt: `## You are calling to remind an attendee about their upcoming appointment in 1 hour. Be friendly, helpful, and concise.
@@
-  },
-};
+  },
+} as const;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 34160b8 and 4200e93.

📒 Files selected for processing (2)
  • packages/features/calAIPhone/promptTemplates.ts (2 hunks)
  • packages/features/calAIPhone/workflowTemplates.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/features/calAIPhone/promptTemplates.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/features/calAIPhone/workflowTemplates.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/features/calAIPhone/workflowTemplates.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • packages/features/calAIPhone/workflowTemplates.ts
🧠 Learnings (5)
📓 Common learnings
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/features/ee/workflows/lib/schema.ts:41-43
Timestamp: 2025-08-14T10:30:23.062Z
Learning: In calcom/cal.com workflows with CAL_AI_PHONE_CALL actions, agentId can legitimately be null during initial setup. The workflow is: 1) save workflow to get step ID, 2) use step ID to create and link agent. Therefore, agentId should remain nullable in schemas to support this multi-step setup process (per maintainer Udit-takkar).
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/trpc/server/routers/viewer/workflows/update.handler.ts:738-763
Timestamp: 2025-08-15T00:07:30.058Z
Learning: In calcom/cal.com workflows, Cal AI phone call actions (CAL_AI_PHONE_CALL) intentionally always require the phone number field when the action is present, unlike SMS/WhatsApp actions which respect the step.numberRequired flag. This is the intended behavior per maintainer Udit-takkar in PR #22995.
📚 Learning: 2025-08-19T08:45:41.834Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/features/ee/workflows/lib/reminders/aiPhoneCallManager.ts:167-193
Timestamp: 2025-08-19T08:45:41.834Z
Learning: In calcom/cal.com AI phone call scheduling (aiPhoneCallManager.ts), workflow reminder records are intentionally kept in the database even when task scheduling fails, as they provide valuable debugging information for troubleshooting scheduling issues, per maintainer Udit-takkar in PR #22995.

Applied to files:

  • packages/features/calAIPhone/workflowTemplates.ts
📚 Learning: 2025-08-08T09:29:11.681Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22919
File: packages/features/calAIPhone/interfaces/AIPhoneService.interface.ts:118-143
Timestamp: 2025-08-08T09:29:11.681Z
Learning: In calcom/cal.com PR #22919, packages/features/calAIPhone/interfaces/AIPhoneService.interface.ts (TypeScript), the AIPhoneServiceAgentListItem is required to include user.email in listAgents responses (per maintainer Udit-takkar). Future reviews should not flag this as unnecessary PII unless requirements change.

Applied to files:

  • packages/features/calAIPhone/workflowTemplates.ts
📚 Learning: 2025-08-26T20:09:17.089Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/features/ee/workflows/components/WorkflowStepContainer.tsx:641-649
Timestamp: 2025-08-26T20:09:17.089Z
Learning: In packages/features/ee/workflows/components/WorkflowStepContainer.tsx, Cal.AI actions are intentionally filtered out/hidden for organization workflows when props.isOrganization is true. This restriction is by design per maintainer Udit-takkar in PR #22995, despite the broader goal of enabling Cal.AI self-serve.

Applied to files:

  • packages/features/calAIPhone/workflowTemplates.ts
📚 Learning: 2025-08-08T10:26:13.362Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22919
File: packages/features/calAIPhone/providers/retellAI/services/PhoneNumberService.ts:212-220
Timestamp: 2025-08-08T10:26:13.362Z
Learning: In calcom/cal.com PR #22919, packages/features/calAIPhone/providers/retellAI/services/PhoneNumberService.ts should include the phone number in client-facing HttpError messages (e.g., in updatePhoneNumber/getPhoneNumber catch blocks). Do not suggest redacting the phone number from these errors unless requirements change (per maintainer: Udit-takkar).

Applied to files:

  • packages/features/calAIPhone/workflowTemplates.ts

Comment on lines +245 to +257
useEffect(() => {
const autoCreateAgent = searchParams?.get("autoCreateAgent");
const templateWorkflowId = searchParams?.get("templateWorkflowId");

if (
autoCreateAgent === "true" &&
!autoAgentCreationAttempted &&
templateWorkflowId &&
step &&
step.action === WorkflowActions.CAL_AI_PHONE_CALL &&
!stepAgentId &&
step.id &&
onSaveWorkflow
Copy link
Member

@hariombalhara hariombalhara Sep 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can avoid useEffect here and we should abstract this complex logic out in its own hook(regardless of whether useEffect is avoidable or not)

const aiService = createDefaultAIPhoneServiceProvider();

const generalPrompt = templateWorkflowId
? calAIPhoneWorkflowTemplates?.[templateWorkflowId as keyof typeof calAIPhoneWorkflowTemplates]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
? calAIPhoneWorkflowTemplates?.[templateWorkflowId as keyof typeof calAIPhoneWorkflowTemplates]
? calAIPhoneWorkflowTemplates.[templateWorkflowId as keyof typeof calAIPhoneWorkflowTemplates]

Don't think calAIPhoneWorkflowTemplates is nullish

@CarinaWolli CarinaWolli merged commit ba50268 into main Sep 10, 2025
64 of 66 checks passed
@CarinaWolli CarinaWolli deleted the feat/auto-create-agent branch September 10, 2025 08:42
Copy link
Member

@hariombalhara hariombalhara left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left an actionable comment otherwise looks good.

@hariombalhara
Copy link
Member

lol, got a bit late @Udit-takkar. See if you can pick the comment up in a follow-up

@github-actions
Copy link
Contributor

E2E results are ready!

@Udit-takkar
Copy link
Contributor Author

lol, got a bit late @Udit-takkar. See if you can pick the comment up in a follow-up

OK got it. just saw your comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai area: AI, cal.ai core area: core, team members only enterprise area: enterprise, audit log, organisation, SAML, SSO ✨ feature New feature or request High priority Created by Linear-GitHub Sync ready-for-e2e size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants