Skip to content

Comments

feat: inbound calls in cal ai#23890

Merged
Udit-takkar merged 49 commits intomainfrom
feat/inbound
Oct 9, 2025
Merged

feat: inbound calls in cal ai#23890
Udit-takkar merged 49 commits intomainfrom
feat/inbound

Conversation

@Udit-takkar
Copy link
Contributor

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

What does this PR do?

This PR adds support for inbound calls where users can call the phone number directly.

Screenshot 2025-09-22 at 5 27 44 PM

  1. Create a workflow and select cal ai voice call as action and finish setup
  2. Buy/import any phone number
  3. Go to incoming calls tab and click on setup button and assign any event type

This PR adds support for inbound calls for cal ai. To be reviewed after #23890 is merged in this branch

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 17, 2025

Walkthrough

Adds full inbound-agent support and splits outbound-agent APIs: renames createAgent → createOutboundAgent and adds createInboundAgent across AI phone service interfaces, providers, SDKs, and tests. Converts Prisma repositories to instance-based classes, updates Prisma schema with Agent.inboundEventTypeId and WorkflowStep.inboundAgentId, and exposes linkOutboundAgentToWorkflow and linkInboundAgentToWorkflow. Adds TRPC routes/handlers for setting up and updating inbound agents, updates workflow handlers to track/delete inbound agents, introduces a new AgentConfigurationSheet and many agent-configuration UI/hooks/forms/utils/locales, and renames phone-number billing flag to disconnectAgents.

Possibly related PRs

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly highlights the primary feature addition of inbound call support in Cal AI and accurately reflects the main purpose of this changeset without extraneous detail or unrelated terms.
Description Check ✅ Passed The description clearly explains that the PR adds support for inbound calls, outlines the user flows, references a screenshot, and directly relates to the changeset without being off-topic or irrelevant.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/inbound

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • 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 ba5525b and c3fbe08.

📒 Files selected for processing (2)
  • apps/web/public/static/locales/en/common.json (3 hunks)
  • packages/prisma/schema.prisma (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/public/static/locales/en/common.json
  • packages/prisma/schema.prisma
⏰ 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). (8)
  • GitHub Check: Production builds / Build API v1
  • GitHub Check: Production builds / Build Web App
  • GitHub Check: Tests / Unit
  • GitHub Check: Production builds / Build Docs
  • GitHub Check: Production builds / Build Atoms
  • GitHub Check: Production builds / Build API v2
  • GitHub Check: Type check / check-types
  • GitHub Check: Linters / lint

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 17, 2025
@vercel
Copy link

vercel bot commented Sep 17, 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 Oct 9, 2025 8:18am
cal-eu Ignored Ignored Oct 9, 2025 8:18am

@Udit-takkar Udit-takkar added the High priority Created by Linear-GitHub Sync label Sep 18, 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: 1

Caution

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

⚠️ Outside diff range comments (4)
packages/features/calAIPhone/providers/retellAI/RetellAIService.test.ts (1)

792-819: Add missing test coverage for createInboundAgent
No test blocks for the newly introduced createInboundAgent method were found; please add a corresponding test (mirroring the createOutboundAgent suite) to ensure full coverage.

packages/features/ee/billing/api/webhook/_customer.subscription.deleted.ts (1)

67-67: Update type annotation to reflect instance method usage.

Line 67 references the static method signature PrismaPhoneNumberRepository.findByStripeSubscriptionId, but the code now uses an instance method. While this likely works due to matching return types, update the type annotation for consistency.

Apply this diff:

 async function handleCalAIPhoneNumberSubscriptionDeleted(
   subscription: Data["object"],
-  phoneNumber: NonNullable<Awaited<ReturnType<typeof PrismaPhoneNumberRepository.findByStripeSubscriptionId>>>
+  phoneNumber: NonNullable<Awaited<ReturnType<PrismaPhoneNumberRepository["findByStripeSubscriptionId"]>>>
 ) {
packages/trpc/server/routers/viewer/aiVoiceAgent/testCall.handler.ts (1)

47-52: CRITICAL: Verify eventType ownership before calling updateToolsFromAgentId.

updateToolsFromAgentId does not perform eventType authorization internally. Before line 47, verify that input.eventTypeId belongs to ctx.user.id or the user's accessible teams (e.g., via EventTypeRepository.findByIdWithUserAccess). Throw a TRPCError with code "FORBIDDEN" if verification fails.

Based on learnings and past review comments.

🤖 Prompt for AI Agents
In packages/trpc/server/routers/viewer/aiVoiceAgent/testCall.handler.ts around
lines 21-52, before calling aiService.updateToolsFromAgentId at line 47, add
eventType ownership verification: instantiate an EventTypeRepository, call a method
like findByIdWithUserAccess with eventTypeId (from input.eventTypeId), userId
(ctx.user.id), and teamId (input.teamId), and throw a TRPCError with code
"FORBIDDEN" or "NOT_FOUND" if the eventType is not accessible; only after
successful verification proceed to call updateToolsFromAgentId.
packages/features/ee/billing/api/webhook/_checkout.session.completed.ts (1)

149-157: Remove duplicate agent fetch.

The agent was already fetched and validated at lines 104-108 with the same parameters (agentId, userId, teamId). Reuse the earlier agent variable instead of querying again.

Apply this diff:

   try {
     console.log("Attempting to link agent to phone number:", { agentId, phoneNumberId: newNumber.id });
 
-    const agent = await agentRepo.findByIdWithUserAccess({
-      agentId,
-      userId,
-    });
-
-    if (!agent) {
-      console.error("Agent not found or user does not have access", { agentId, userId });
-      throw new HttpCode(404, "Agent not found or user does not have access to it");
-    }
-
+    // Reuse agent from line 104
     console.log("Found agent:", { agentId: agent.id, providerAgentId: agent.providerAgentId });
♻️ Duplicate comments (5)
packages/trpc/server/routers/viewer/aiVoiceAgent/updateInboundAgentEventType.handler.ts (1)

43-48: CRITICAL: Verify eventType ownership before calling updateToolsFromAgentId.

updateToolsFromAgentId does not enforce eventType RBAC internally. A malicious user could point tools at an eventType they don't own, potentially causing API failures or unauthorized data access.

Before line 43, fetch and verify that eventTypeId belongs to ctx.user.id or the user's accessible teams using an RBAC-aware repository method (e.g., EventTypeRepository.findByIdWithUserAccess). Throw 403/404 if verification fails.

Based on learnings and past review comments.

🤖 Prompt for AI Agents
In packages/trpc/server/routers/viewer/aiVoiceAgent/updateInboundAgentEventType.handler.ts
around lines 29-48, before calling aiService.updateToolsFromAgentId, add eventType
ownership verification: instantiate an EventTypeRepository (or use an existing RBAC
helper), call a method like findByIdWithUserAccess with eventTypeId, userId, and
teamId (or similar parameters), and throw a TRPCError with code "FORBIDDEN" or
"NOT_FOUND" if the eventType is not returned or user lacks access; only after
successful verification proceed to call updateToolsFromAgentId.
apps/web/app/api/webhooks/retell-ai/route.ts (1)

172-175: Missing import: prisma is not defined.

Line 172 creates new PrismaPhoneNumberRepository(prisma), but prisma is not imported. This will cause a runtime error.

Add the missing import at the top of the file (same fix as above):

+import prisma from "@calcom/prisma";
 import { CreditService } from "@calcom/features/ee/billing/credit-service";
packages/lib/server/repository/PrismaAgentRepository.ts (1)

590-599: Validate eventTypeId ownership in service layer

  • In updateInboundAgentEventTypeHandler, after confirming agent access via getAgentWithDetails, add a check that eventTypeId belongs to the same user/team (e.g. fetch the EventType with teamId and error if not found) before calling PrismaAgentRepository.updateEventTypeId.
packages/lib/server/repository/PrismaPhoneNumberRepository.ts (2)

436-464: Implementation looks correct; interface and caller updates pending.

The dual-disconnect behavior for both inbound and outbound agents is correctly implemented. As noted in previous reviews, ensure the interface and callers are updated to use the new disconnectAgents parameter.


525-572: LGTM! Atomic set-if-unset correctly implemented.

The method uses updateMany with a conditional WHERE clause to atomically set the inbound agent only if unset. The count-based success check and fallback query for conflict detection are correct.

🧹 Nitpick comments (4)
packages/features/ee/billing/api/webhook/_customer.subscription.updated.ts (1)

49-56: Consider using repository pattern for the update operation.

While the query operation now uses the repository pattern (line 18), this update still directly calls prisma.calAiPhoneNumber.update. For consistency and better separation of concerns, consider adding an updateSubscriptionStatus method to PrismaPhoneNumberRepository and using it here.

This would consolidate all phone number database operations in the repository:

const subscriptionStatus = statusMap[subscription.status] || PhoneNumberSubscriptionStatus.UNPAID;

await phoneNumberRepo.updateSubscriptionStatus({
  id: phoneNumber.id,
  status: subscriptionStatus,
});

And in PrismaPhoneNumberRepository:

async updateSubscriptionStatus({ id, status }: { id: number; status: PhoneNumberSubscriptionStatus }) {
  return await this.prismaClient.calAiPhoneNumber.update({
    where: { id },
    data: { subscriptionStatus: status },
  });
}
packages/features/ee/billing/api/webhook/_checkout.session.completed.ts (1)

167-174: Prefer repository method over direct Prisma call for consistency.

Direct prisma.calAiPhoneNumber.update bypasses the repository abstraction. If PrismaPhoneNumberRepository has an updateAgents or similar method (as indicated in relevant code snippets), use it instead for consistency.

If phoneNumberRepo.updateAgents supports linking agents, apply this pattern:

-    await prisma.calAiPhoneNumber.update({
-      where: { id: newNumber.id },
-      data: {
-        outboundAgent: {
-          connect: { id: agentId },
-        },
-      },
-    });
+    await phoneNumberRepo.updateAgents({
+      id: newNumber.id,
+      outboundProviderAgentId: agent.providerAgentId,
+    });
packages/features/calAIPhone/providers/adapters/PrismaAgentRepositoryAdapter.ts (1)

14-81: Consider reusing a single PrismaAgentRepository instance.

Each method creates a new PrismaAgentRepository(prisma) instance, which adds unnecessary object allocation overhead. Consider creating the repository once in the adapter constructor and reusing it across all methods.

Apply this pattern:

 export class PrismaAgentRepositoryAdapter implements AgentRepositoryInterface {
+  private agentRepo: PrismaAgentRepository;
+
+  constructor() {
+    this.agentRepo = new PrismaAgentRepository(prisma);
+  }
+
   async canManageTeamResources(params: { userId: number; teamId: number }): Promise<boolean> {
-    const agentRepo = new PrismaAgentRepository(prisma);
-    return await agentRepo.canManageTeamResources(params);
+    return await this.agentRepo.canManageTeamResources(params);
   }

Then apply the same pattern to all other methods.

packages/features/calAIPhone/providers/adapters/PrismaPhoneNumberRepositoryAdapter.ts (1)

14-89: Consider reusing a single PrismaPhoneNumberRepository instance.

Similar to the agent adapter, each method creates a new PrismaPhoneNumberRepository(prisma) instance. Consider creating the repository once in the constructor and reusing it.

Apply this pattern:

 export class PrismaPhoneNumberRepositoryAdapter implements PhoneNumberRepositoryInterface {
+  private phoneNumberRepo: PrismaPhoneNumberRepository;
+
+  constructor() {
+    this.phoneNumberRepo = new PrismaPhoneNumberRepository(prisma);
+  }
+
   async findByPhoneNumberAndUserId(params: {
     phoneNumber: string;
     userId: number;
   }): Promise<PhoneNumberData | null> {
-    const phoneNumberRepo = new PrismaPhoneNumberRepository(prisma);
-    return await phoneNumberRepo.findByPhoneNumberAndUserId(params);
+    return await this.phoneNumberRepo.findByPhoneNumberAndUserId(params);
   }

Then apply to all other methods.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • 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 50d3214 and c3e19ee.

📒 Files selected for processing (14)
  • apps/web/app/api/webhooks/retell-ai/__tests__/route.test.ts (19 hunks)
  • apps/web/app/api/webhooks/retell-ai/route.ts (2 hunks)
  • packages/features/calAIPhone/providers/adapters/PrismaAgentRepositoryAdapter.ts (3 hunks)
  • packages/features/calAIPhone/providers/adapters/PrismaPhoneNumberRepositoryAdapter.ts (3 hunks)
  • packages/features/calAIPhone/providers/retellAI/RetellAIService.test.ts (9 hunks)
  • packages/features/calAIPhone/providers/retellAI/types.ts (4 hunks)
  • packages/features/ee/billing/api/webhook/_checkout.session.completed.ts (4 hunks)
  • packages/features/ee/billing/api/webhook/_customer.subscription.deleted.ts (2 hunks)
  • packages/features/ee/billing/api/webhook/_customer.subscription.updated.ts (2 hunks)
  • packages/lib/server/repository/PrismaAgentRepository.ts (22 hunks)
  • packages/lib/server/repository/PrismaPhoneNumberRepository.ts (19 hunks)
  • packages/trpc/server/routers/viewer/aiVoiceAgent/testCall.handler.ts (2 hunks)
  • packages/trpc/server/routers/viewer/aiVoiceAgent/updateInboundAgentEventType.handler.ts (1 hunks)
  • packages/trpc/server/routers/viewer/phoneNumber/list.handler.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/app/api/webhooks/retell-ai/tests/route.test.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.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/adapters/PrismaPhoneNumberRepositoryAdapter.ts
  • packages/trpc/server/routers/viewer/aiVoiceAgent/updateInboundAgentEventType.handler.ts
  • packages/features/ee/billing/api/webhook/_customer.subscription.updated.ts
  • packages/features/ee/billing/api/webhook/_checkout.session.completed.ts
  • packages/lib/server/repository/PrismaAgentRepository.ts
  • packages/features/calAIPhone/providers/retellAI/types.ts
  • packages/features/calAIPhone/providers/adapters/PrismaAgentRepositoryAdapter.ts
  • packages/features/ee/billing/api/webhook/_customer.subscription.deleted.ts
  • packages/features/calAIPhone/providers/retellAI/RetellAIService.test.ts
  • packages/trpc/server/routers/viewer/aiVoiceAgent/testCall.handler.ts
  • apps/web/app/api/webhooks/retell-ai/route.ts
  • packages/lib/server/repository/PrismaPhoneNumberRepository.ts
  • packages/trpc/server/routers/viewer/phoneNumber/list.handler.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/adapters/PrismaPhoneNumberRepositoryAdapter.ts
  • packages/trpc/server/routers/viewer/aiVoiceAgent/updateInboundAgentEventType.handler.ts
  • packages/features/ee/billing/api/webhook/_customer.subscription.updated.ts
  • packages/features/ee/billing/api/webhook/_checkout.session.completed.ts
  • packages/lib/server/repository/PrismaAgentRepository.ts
  • packages/features/calAIPhone/providers/retellAI/types.ts
  • packages/features/calAIPhone/providers/adapters/PrismaAgentRepositoryAdapter.ts
  • packages/features/ee/billing/api/webhook/_customer.subscription.deleted.ts
  • packages/features/calAIPhone/providers/retellAI/RetellAIService.test.ts
  • packages/trpc/server/routers/viewer/aiVoiceAgent/testCall.handler.ts
  • apps/web/app/api/webhooks/retell-ai/route.ts
  • packages/lib/server/repository/PrismaPhoneNumberRepository.ts
  • packages/trpc/server/routers/viewer/phoneNumber/list.handler.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/adapters/PrismaPhoneNumberRepositoryAdapter.ts
  • packages/trpc/server/routers/viewer/aiVoiceAgent/updateInboundAgentEventType.handler.ts
  • packages/features/ee/billing/api/webhook/_customer.subscription.updated.ts
  • packages/features/ee/billing/api/webhook/_checkout.session.completed.ts
  • packages/lib/server/repository/PrismaAgentRepository.ts
  • packages/features/calAIPhone/providers/retellAI/types.ts
  • packages/features/calAIPhone/providers/adapters/PrismaAgentRepositoryAdapter.ts
  • packages/features/ee/billing/api/webhook/_customer.subscription.deleted.ts
  • packages/features/calAIPhone/providers/retellAI/RetellAIService.test.ts
  • packages/trpc/server/routers/viewer/aiVoiceAgent/testCall.handler.ts
  • apps/web/app/api/webhooks/retell-ai/route.ts
  • packages/lib/server/repository/PrismaPhoneNumberRepository.ts
  • packages/trpc/server/routers/viewer/phoneNumber/list.handler.ts
**/*Repository.ts

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

Repository files must include Repository suffix, prefix with technology if applicable (e.g., PrismaAppRepository.ts), and use PascalCase matching the exported class

Files:

  • packages/lib/server/repository/PrismaAgentRepository.ts
  • packages/lib/server/repository/PrismaPhoneNumberRepository.ts
🧠 Learnings (9)
📓 Common learnings
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.
📚 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/updateInboundAgentEventType.handler.ts
📚 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/updateInboundAgentEventType.handler.ts
  • packages/trpc/server/routers/viewer/aiVoiceAgent/testCall.handler.ts
📚 Learning: 2025-08-27T12:15:43.830Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/trpc/server/routers/viewer/aiVoiceAgent/testCall.handler.ts:41-44
Timestamp: 2025-08-27T12:15:43.830Z
Learning: In calcom/cal.com, the AgentService.getAgent() method in packages/features/calAIPhone/providers/retellAI/services/AgentService.ts does NOT include authorization checks - it only validates the agentId parameter and directly calls the repository without verifying user/team access. This contrasts with other methods like getAgentWithDetails() which properly use findByIdWithUserAccessAndDetails() for authorization. When reviewing updateToolsFromAgentId() calls, always verify both agent ownership and eventType ownership are checked.

Applied to files:

  • packages/trpc/server/routers/viewer/aiVoiceAgent/updateInboundAgentEventType.handler.ts
  • packages/lib/server/repository/PrismaAgentRepository.ts
  • packages/features/calAIPhone/providers/retellAI/types.ts
📚 Learning: 2025-08-26T20:23:28.396Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/features/calAIPhone/providers/retellAI/services/AgentService.ts:83-88
Timestamp: 2025-08-26T20:23:28.396Z
Learning: In calcom/cal.com PR #22995, the workflow update handler in packages/trpc/server/routers/viewer/workflows/update.handler.ts includes workflow-level authorization via isAuthorized(userWorkflow, ctx.user.id, "workflow.update") which validates the user can update the workflow before calling updateToolsFromAgentId (per maintainer Udit-takkar).

Applied to files:

  • packages/trpc/server/routers/viewer/aiVoiceAgent/updateInboundAgentEventType.handler.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/trpc/server/routers/viewer/aiVoiceAgent/updateInboundAgentEventType.handler.ts
  • packages/features/calAIPhone/providers/retellAI/types.ts
  • packages/features/calAIPhone/providers/retellAI/RetellAIService.test.ts
📚 Learning: 2025-09-09T03:29:43.025Z
Learnt from: emrysal
PR: calcom/cal.com#23692
File: packages/lib/server/service/InsightsBookingBaseService.ts:16-16
Timestamp: 2025-09-09T03:29:43.025Z
Learning: In the Cal.com codebase, readonlyPrisma is still an instance of PrismaClient, making type changes from `typeof readonlyPrisma` to `PrismaClient` less critical since they are fundamentally compatible types.

Applied to files:

  • packages/lib/server/repository/PrismaAgentRepository.ts
  • packages/lib/server/repository/PrismaPhoneNumberRepository.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/providers/retellAI/types.ts
📚 Learning: 2025-08-21T16:34:10.839Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/trpc/server/routers/viewer/phoneNumber/delete.handler.ts:13-24
Timestamp: 2025-08-21T16:34:10.839Z
Learning: In calcom/cal.com PR #22995, the deletePhoneNumber function in packages/trpc/server/routers/viewer/phoneNumber/delete.handler.ts is only used for imported phone numbers that don't have active Stripe subscriptions. Purchased phone numbers with subscriptions use a separate cancellation flow first (per maintainer Udit-takkar).

Applied to files:

  • packages/lib/server/repository/PrismaPhoneNumberRepository.ts
  • packages/trpc/server/routers/viewer/phoneNumber/list.handler.ts
🧬 Code graph analysis (12)
packages/features/calAIPhone/providers/adapters/PrismaPhoneNumberRepositoryAdapter.ts (2)
packages/lib/server/repository/PrismaPhoneNumberRepository.ts (1)
  • PrismaPhoneNumberRepository (26-589)
packages/features/calAIPhone/providers/interfaces/PhoneNumberRepositoryInterface.ts (1)
  • PhoneNumberData (90-103)
packages/trpc/server/routers/viewer/aiVoiceAgent/updateInboundAgentEventType.handler.ts (3)
packages/trpc/server/routers/viewer/aiVoiceAgent/updateInboundAgentEventType.schema.ts (1)
  • TUpdateInboundAgentEventTypeInputSchema (9-9)
packages/features/ee/workflows/components/agent-configuration/utils/promptUtils.ts (1)
  • replaceEventTypePlaceholders (28-40)
packages/lib/server/repository/PrismaAgentRepository.ts (1)
  • PrismaAgentRepository (31-619)
packages/features/ee/billing/api/webhook/_customer.subscription.updated.ts (1)
packages/lib/server/repository/PrismaPhoneNumberRepository.ts (1)
  • PrismaPhoneNumberRepository (26-589)
packages/features/ee/billing/api/webhook/_checkout.session.completed.ts (2)
packages/lib/server/repository/PrismaAgentRepository.ts (1)
  • PrismaAgentRepository (31-619)
packages/lib/server/repository/PrismaPhoneNumberRepository.ts (1)
  • PrismaPhoneNumberRepository (26-589)
packages/lib/server/repository/PrismaAgentRepository.ts (1)
packages/prisma/index.ts (1)
  • PrismaClient (84-84)
packages/features/calAIPhone/providers/retellAI/types.ts (1)
packages/lib/server/repository/PrismaAgentRepository.ts (1)
  • PrismaAgentRepository (31-619)
packages/features/calAIPhone/providers/adapters/PrismaAgentRepositoryAdapter.ts (2)
packages/lib/server/repository/PrismaAgentRepository.ts (1)
  • PrismaAgentRepository (31-619)
packages/features/calAIPhone/providers/interfaces/AgentRepositoryInterface.ts (3)
  • AgentData (82-92)
  • AgentWithDetailsData (97-115)
  • AgentWithPhoneNumbersData (120-124)
packages/features/ee/billing/api/webhook/_customer.subscription.deleted.ts (1)
packages/lib/server/repository/PrismaPhoneNumberRepository.ts (1)
  • PrismaPhoneNumberRepository (26-589)
packages/trpc/server/routers/viewer/aiVoiceAgent/testCall.handler.ts (1)
packages/lib/server/repository/PrismaAgentRepository.ts (1)
  • PrismaAgentRepository (31-619)
apps/web/app/api/webhooks/retell-ai/route.ts (2)
packages/lib/server/repository/PrismaAgentRepository.ts (1)
  • PrismaAgentRepository (31-619)
packages/lib/server/repository/PrismaPhoneNumberRepository.ts (1)
  • PrismaPhoneNumberRepository (26-589)
packages/lib/server/repository/PrismaPhoneNumberRepository.ts (1)
packages/prisma/index.ts (1)
  • PrismaClient (84-84)
packages/trpc/server/routers/viewer/phoneNumber/list.handler.ts (1)
packages/lib/server/repository/PrismaPhoneNumberRepository.ts (1)
  • PrismaPhoneNumberRepository (26-589)
⏰ 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). (7)
  • GitHub Check: Production builds / Build Web App
  • GitHub Check: Production builds / Build Atoms
  • GitHub Check: Production builds / Build API v2
  • GitHub Check: Production builds / Build API v1
  • GitHub Check: Tests / Unit
  • GitHub Check: Linters / lint
  • GitHub Check: Type check / check-types
🔇 Additional comments (34)
packages/features/ee/billing/api/webhook/_customer.subscription.updated.ts (1)

1-20: Migration to instance-based repository pattern looks correct.

The change correctly instantiates PrismaPhoneNumberRepository with the Prisma client and calls the instance method findByStripeSubscriptionId. The pattern aligns with the repository class definition and maintains the existing error handling logic.

packages/features/calAIPhone/providers/retellAI/RetellAIService.test.ts (5)

83-83: LGTM! Mock updated to reflect outbound agent API.

The mock repository and agent repository methods have been correctly updated to use createOutboundAgent and linkOutboundAgentToWorkflow, aligning with the inbound/outbound agent split introduced in this PR.

Also applies to: 107-107


171-171: LGTM! Test mocks updated for outbound agent creation.

The test correctly mocks createOutboundAgent instead of the old createAgent method, aligning with the new API surface.

Also applies to: 194-194


545-545: LGTM! Test expectation updated to undefined.

The test now expects general_tools: undefined instead of null, reflecting the updated contract of the updateLLMConfiguration method.


711-711: LGTM! Parameter renamed to support both agent types.

The test expectation correctly uses disconnectAgents: true instead of disconnectOutboundAgent, reflecting the generalized API that handles both inbound and outbound agents.


983-983: LGTM! Error handling test unchanged.

The mock correctly returns null to test the error path when an agent is not found. No substantive changes detected.

packages/features/ee/billing/api/webhook/_customer.subscription.deleted.ts (1)

16-20: LGTM: Instance-based repository pattern correctly applied.

The switch from static PrismaPhoneNumberRepository.findByStripeSubscriptionId to instance-based phoneNumberRepo.findByStripeSubscriptionId(...) aligns with the PR-wide migration to dependency-injected Prisma repositories.

packages/trpc/server/routers/viewer/aiVoiceAgent/updateInboundAgentEventType.handler.ts (2)

50-55: LGTM: teamId now included in updateAgentConfiguration.

Correctly passes teamId to updateAgentConfiguration, ensuring proper admin-access scoping for team-owned agents. This addresses the issue flagged in past reviews.


57-61: LGTM: Repository instantiation follows PR pattern.

Instance-based PrismaAgentRepository(prisma) usage aligns with the project-wide migration to dependency-injected repositories.

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

30-34: LGTM: Instance-based repository pattern correctly applied.

Properly instantiates PrismaAgentRepository(prisma) and calls the instance method findByIdWithCallAccess. This aligns with the PR-wide repository refactor.

packages/trpc/server/routers/viewer/phoneNumber/list.handler.ts (1)

15-20: LGTM: Instance-based repository pattern correctly applied.

Instantiates PrismaPhoneNumberRepository(prisma) and calls the instance method findManyWithUserAccess. This aligns with the PR-wide migration to dependency-injected Prisma repositories.

packages/features/ee/billing/api/webhook/_checkout.session.completed.ts (2)

103-108: LGTM: Instance-based repository pattern correctly applied.

Properly instantiates PrismaAgentRepository(prisma) and calls the instance method findByIdWithUserAccess.


134-144: LGTM: Instance-based repository pattern correctly applied.

Correctly instantiates PrismaPhoneNumberRepository(prisma) and calls createPhoneNumber.

packages/features/calAIPhone/providers/retellAI/types.ts (3)

105-107: LGTM: Type reference updated for instance-based repository.

The change from typeof PrismaAgentRepository.findByIdWithUserAccessAndDetails to indexed access PrismaAgentRepository["findByIdWithUserAccessAndDetails"] correctly reflects the migration from static methods to instance methods.


116-116: LGTM: inboundEventTypeId added to support inbound agent feature.

This field enables linking inbound agents to event types, aligning with the PR's inbound call functionality.


171-171: LGTM: Method renamed to clarify outbound agent creation.

Renaming createAgent to createOutboundAgent aligns with the PR's outbound/inbound agent separation.

packages/features/calAIPhone/providers/adapters/PrismaAgentRepositoryAdapter.ts (1)

83-91: LGTM: Outbound and inbound agent linkage methods correctly implemented.

The split between linkOutboundAgentToWorkflow and linkInboundAgentToWorkflow properly separates the two flows and addresses the past review feedback about clarifying the outbound agent linkage.

packages/features/calAIPhone/providers/adapters/PrismaPhoneNumberRepositoryAdapter.ts (1)

91-97: LGTM: Atomic inbound agent assignment method added.

The setInboundProviderAgentIdIfUnset method properly delegates to the repository's atomic update logic, which prevents race conditions when assigning inbound agents to phone numbers.

packages/lib/server/repository/PrismaAgentRepository.ts (3)

31-32: LGTM: Constructor-based dependency injection implemented.

The migration from static methods to instance methods with constructor(private prismaClient: PrismaClient) enables proper dependency injection and testing.


103-103: LGTM: inboundEventTypeId consistently added across all queries.

The inboundEventTypeId field is properly included in all relevant SELECT queries and result mappings, supporting the inbound agent feature.

Also applies to: 142-142, 164-164, 183-183, 248-248, 308-308, 368-368, 410-410, 495-495, 526-526


560-588: LGTM: Outbound and inbound workflow linkage methods properly separated.

The split between linkOutboundAgentToWorkflow (sets agentId) and linkInboundAgentToWorkflow (sets inboundAgentId) correctly supports the dual agent model.

packages/lib/server/repository/PrismaPhoneNumberRepository.ts (13)

1-27: LGTM! Clean dependency injection pattern.

The constructor correctly accepts a PrismaClient instance, enabling testability and loose coupling. Interface definitions are clear and appropriately typed.


29-41: LGTM!

The method correctly queries user memberships and returns accessible team IDs. The migration to instance method is consistent with the new DI pattern.


43-64: LGTM!

The method correctly queries by phone number and user ID. The use of findFirstOrThrow provides clear error handling semantics.


66-140: LGTM!

The raw SQL queries are well-structured and efficiently fetch phone numbers with their associated inbound/outbound agents. The mapping logic correctly categorizes agents by type and combines results.


142-188: LGTM!

The method correctly creates a phone number record with all necessary fields. The selection is comprehensive and includes the new inbound/outbound agent fields.


190-196: LGTM!

The delete operation is straightforward and correctly uses the instance method pattern.


198-214: LGTM!

The method correctly queries by Stripe subscription ID. The selection excludes agent fields, which appears intentional for billing-focused operations.


216-237: LGTM!

The method correctly queries by ID and user ID with comprehensive field selection including agent references.


239-274: LGTM!

The method correctly enforces team access control before querying. The null return for unauthorized access is appropriate.


276-311: LGTM!

The method correctly enforces team access control and queries by phone number and team ID.


313-434: LGTM!

The scope-based filtering logic is well-structured and correctly handles personal, team, and combined access patterns. The dynamic SQL construction uses Prisma's safe parameterization.


466-523: LGTM!

The method correctly handles updating both inbound and outbound agents, with proper lookup and connect/disconnect logic for each.


574-588: LGTM! Enhanced context selection.

The method correctly queries by phone number and returns enriched context including user and team details via nested selects.

@Udit-takkar
Copy link
Contributor Author

@volnei Done

@Udit-takkar Udit-takkar requested a review from volnei October 6, 2025 07:42
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/providers/retellAI/services/AgentService.ts (3)

565-570: Check the correct field for existing inbound agent.

The code checks phoneNumberRecord.inboundAgentId, but the record stores the local agent ID. To verify whether an inbound agent is already configured on the Retell side, you should check phoneNumberRecord.inboundProviderAgentId instead.

Apply this diff:

-    if (phoneNumberRecord.inboundAgentId) {
+    if (phoneNumberRecord.inboundProviderAgentId) {
       throw new HttpError({
         statusCode: 400,
         message: "Inbound agent already configured for this phone number",
       });
     }

572-614: Add error handling with compensating rollback.

The inbound agent creation sequence (create agent → link workflow → update Retell phone → update local phone record) lacks error handling. If any step fails mid-flow, you'll have inconsistent state between Retell and the local database.

Wrap the flow in try/catch and implement compensating rollback actions: on error, attempt to revert the Retell phone update (clear inbound_agent_id), unlink the workflow-to-agent association, delete the newly created local agent record, and log rollback failures separately while re-throwing the original error.


655-658: Guard against undefined generalPrompt.

The code can call replaceEventTypePlaceholders with an undefined generalPrompt if the caller omits it, causing a runtime error. Add a check to ensure generalPrompt is defined before calling the function.

Apply this diff:

     const updatedPrompt =
-      agent.inboundEventTypeId && generalPrompt
+      agent.inboundEventTypeId && generalPrompt != null
         ? replaceEventTypePlaceholders(generalPrompt, agent.inboundEventTypeId)
         : generalPrompt;
🧹 Nitpick comments (1)
packages/features/calAIPhone/providers/adapters/PrismaPhoneNumberRepositoryAdapter.ts (1)

19-20: Consider caching the repository instance.

Every adapter method creates a new PrismaPhoneNumberRepository(prisma) instance. Since prisma is a singleton, consider creating the repository instance once in the adapter's constructor and reusing it.

Apply this diff:

 export class PrismaPhoneNumberRepositoryAdapter implements PhoneNumberRepositoryInterface {
+  private readonly repository: PrismaPhoneNumberRepository;
+
+  constructor() {
+    this.repository = new PrismaPhoneNumberRepository(prisma);
+  }
+
   async findByPhoneNumberAndUserId(params: {
     phoneNumber: string;
     userId: number;
   }): Promise<PhoneNumberData | null> {
-    const phoneNumberRepo = new PrismaPhoneNumberRepository(prisma);
-    return await phoneNumberRepo.findByPhoneNumberAndUserId(params);
+    return await this.repository.findByPhoneNumberAndUserId(params);
   }
   // ... apply similar changes to all other methods

Also applies to: 28-29, 33-34, 42-43, 53-61, 65-66, 74-75, 83-88, 92-93, 99-100

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • 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 ffd67cd and 52820a0.

📒 Files selected for processing (5)
  • packages/features/calAIPhone/providers/adapters/PrismaPhoneNumberRepositoryAdapter.ts (3 hunks)
  • packages/features/calAIPhone/providers/interfaces/PhoneNumberRepositoryInterface.ts (2 hunks)
  • packages/features/calAIPhone/providers/retellAI/services/AgentService.ts (22 hunks)
  • packages/lib/server/repository/PrismaPhoneNumberRepository.ts (19 hunks)
  • packages/trpc/server/routers/viewer/aiVoiceAgent/setupInboundAgent.handler.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/trpc/server/routers/viewer/aiVoiceAgent/setupInboundAgent.handler.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.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/interfaces/PhoneNumberRepositoryInterface.ts
  • packages/features/calAIPhone/providers/retellAI/services/AgentService.ts
  • packages/features/calAIPhone/providers/adapters/PrismaPhoneNumberRepositoryAdapter.ts
  • packages/lib/server/repository/PrismaPhoneNumberRepository.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/interfaces/PhoneNumberRepositoryInterface.ts
  • packages/features/calAIPhone/providers/retellAI/services/AgentService.ts
  • packages/features/calAIPhone/providers/adapters/PrismaPhoneNumberRepositoryAdapter.ts
  • packages/lib/server/repository/PrismaPhoneNumberRepository.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/interfaces/PhoneNumberRepositoryInterface.ts
  • packages/features/calAIPhone/providers/retellAI/services/AgentService.ts
  • packages/features/calAIPhone/providers/adapters/PrismaPhoneNumberRepositoryAdapter.ts
  • packages/lib/server/repository/PrismaPhoneNumberRepository.ts
**/*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/AgentService.ts
**/*Repository.ts

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

Repository files must include Repository suffix, prefix with technology if applicable (e.g., PrismaAppRepository.ts), and use PascalCase matching the exported class

Files:

  • packages/lib/server/repository/PrismaPhoneNumberRepository.ts
🧠 Learnings (7)
📚 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/providers/interfaces/PhoneNumberRepositoryInterface.ts
  • packages/features/calAIPhone/providers/retellAI/services/AgentService.ts
📚 Learning: 2025-08-27T12:15:43.830Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/trpc/server/routers/viewer/aiVoiceAgent/testCall.handler.ts:41-44
Timestamp: 2025-08-27T12:15:43.830Z
Learning: In calcom/cal.com, the AgentService.getAgent() method in packages/features/calAIPhone/providers/retellAI/services/AgentService.ts does NOT include authorization checks - it only validates the agentId parameter and directly calls the repository without verifying user/team access. This contrasts with other methods like getAgentWithDetails() which properly use findByIdWithUserAccessAndDetails() for authorization. When reviewing updateToolsFromAgentId() calls, always verify both agent ownership and eventType ownership are checked.

Applied to files:

  • packages/features/calAIPhone/providers/retellAI/services/AgentService.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/AgentService.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/providers/retellAI/services/AgentService.ts
📚 Learning: 2025-08-14T23:07:45.282Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/features/calAIPhone/providers/retellAI/services/PhoneNumberService.ts:312-319
Timestamp: 2025-08-14T23:07:45.282Z
Learning: In calcom/cal.com phone number import flow, an agent must always be present when importing a phone number. The validateAgentPermissions function in PhoneNumberService should throw a 400 error when agentId is missing, as this is a business requirement rather than optional functionality (per maintainer Udit-takkar).

Applied to files:

  • packages/features/calAIPhone/providers/retellAI/services/AgentService.ts
📚 Learning: 2025-09-09T03:29:43.025Z
Learnt from: emrysal
PR: calcom/cal.com#23692
File: packages/lib/server/service/InsightsBookingBaseService.ts:16-16
Timestamp: 2025-09-09T03:29:43.025Z
Learning: In the Cal.com codebase, readonlyPrisma is still an instance of PrismaClient, making type changes from `typeof readonlyPrisma` to `PrismaClient` less critical since they are fundamentally compatible types.

Applied to files:

  • packages/lib/server/repository/PrismaPhoneNumberRepository.ts
📚 Learning: 2025-08-21T16:34:10.839Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/trpc/server/routers/viewer/phoneNumber/delete.handler.ts:13-24
Timestamp: 2025-08-21T16:34:10.839Z
Learning: In calcom/cal.com PR #22995, the deletePhoneNumber function in packages/trpc/server/routers/viewer/phoneNumber/delete.handler.ts is only used for imported phone numbers that don't have active Stripe subscriptions. Purchased phone numbers with subscriptions use a separate cancellation flow first (per maintainer Udit-takkar).

Applied to files:

  • packages/lib/server/repository/PrismaPhoneNumberRepository.ts
🧬 Code graph analysis (3)
packages/features/calAIPhone/providers/retellAI/services/AgentService.ts (5)
packages/features/calAIPhone/providers/retellAI/types.ts (1)
  • RetellAIRepository (163-194)
packages/features/calAIPhone/providers/interfaces/AgentRepositoryInterface.ts (1)
  • AgentRepositoryInterface (6-77)
packages/features/calAIPhone/providers/interfaces/PhoneNumberRepositoryInterface.ts (1)
  • PhoneNumberRepositoryInterface (8-87)
packages/features/ee/workflows/components/agent-configuration/utils/promptUtils.ts (1)
  • replaceEventTypePlaceholders (28-40)
packages/features/calAIPhone/providers/retellAI/RetellAIServiceMapper.ts (1)
  • RetellAIServiceMapper (24-210)
packages/features/calAIPhone/providers/adapters/PrismaPhoneNumberRepositoryAdapter.ts (2)
packages/lib/server/repository/PrismaPhoneNumberRepository.ts (1)
  • PrismaPhoneNumberRepository (26-564)
packages/features/calAIPhone/providers/interfaces/PhoneNumberRepositoryInterface.ts (1)
  • PhoneNumberData (92-105)
packages/lib/server/repository/PrismaPhoneNumberRepository.ts (1)
packages/prisma/index.ts (1)
  • PrismaClient (84-84)
⏰ 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 (10)
packages/features/calAIPhone/providers/retellAI/services/AgentService.ts (1)

24-32: LGTM!

The Dependencies type and constructor refactor improves maintainability by consolidating all dependencies into a single object.

Based on learnings

packages/features/calAIPhone/providers/interfaces/PhoneNumberRepositoryInterface.ts (2)

66-66: LGTM!

Renaming disconnectOutboundAgent to disconnectAgents accurately reflects that both inbound and outbound agents are now disconnected.


78-86: LGTM!

The new methods updateInboundAgentId and findInboundAgentIdByPhoneNumberId support atomic inbound agent setup and race condition detection.

packages/features/calAIPhone/providers/adapters/PrismaPhoneNumberRepositoryAdapter.ts (2)

91-94: LGTM!

The new updateInboundAgentId method correctly delegates to the repository's atomic update operation.


96-101: LGTM!

The new findInboundAgentIdByPhoneNumberId method correctly delegates to the repository for race condition detection.

packages/lib/server/repository/PrismaPhoneNumberRepository.ts (5)

27-27: LGTM!

Converting to an instance-based repository with constructor injection improves testability and allows for different PrismaClient instances (e.g., for testing or multi-tenant scenarios).


436-464: LGTM!

The renamed disconnectAgents parameter and dual-disconnect logic (both inbound and outbound agents) align with the PR's intent to support inbound calls.


525-540: LGTM!

The atomic updateInboundAgentId using updateMany with a NULL check correctly prevents race conditions. The caller can check count === 0 to detect concurrent setup attempts.


542-547: LGTM!

The findInboundAgentIdByPhoneNumberId method supports race condition detection by allowing the caller to verify which agent was actually configured.


549-563: LGTM!

Enriching findByPhoneNumber with user and team information supports better context in logs or error messages when handling phone number operations.

Copy link
Contributor

@emrysal emrysal left a comment

Choose a reason for hiding this comment

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

Happy for this, lgtm

@Udit-takkar Udit-takkar merged commit aa48e72 into main Oct 9, 2025
38 checks passed
@Udit-takkar Udit-takkar deleted the feat/inbound branch October 9, 2025 10:40
joeauyeung pushed a commit that referenced this pull request Oct 9, 2025
* feat: lang support

* fix: type errors

* feat: select voice agent

* refactor: address feedback

* refactor: address feedback

* refactor: missing import

* fix: types

* feat: add inbound calls

* chore: formatting

* chore

* feat: finish inbound call

* chore: formatting

* fix: update bug

* fix: types

* refactor: Agent Configuration Sheet (#23930)

* refactor: agent configuration sheet

* chore: use default phone numbre

* refactor: improvements

* refactor: improvements

* fix: types

* fix: feedback

* chore:

* fix: feedback

* fix: prompt

* fix: review

* fix: review

* refactor: class

* refactor: class

* refactor: rename

* Update apps/web/public/static/locales/en/common.json

* Update apps/web/public/static/locales/en/common.json

* chore: update set value

* fix: remove index

* fix: type error

* fix: update tetss

* fix: use logger

* refactor: don't use static

* fix: type

* fix: schema

* refactor:

---------

Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
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 ❗️ migrations contains migration files ready-for-e2e size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants