AI agent and config models

AiAgent

Table ai_agents.

Field Type Notes

name

String

type

AiAgentType

analysis, caller, sms, other

llmModelType

AiAgentLlmModelType

gpt or claude; the legacy fallback

subscriptionId

String? @db.Uuid

Nullable, allowing a shared agent across workspaces

modelId

String?

Vercel AI Gateway slug, e.g. openai/gpt-5. Takes precedence over llmModelType

retellAgentId

String? @unique

Retell agent_id; set only for caller agents linked to Retell

latestVersionId

String? @db.Uuid

The published version; null only before the first version exists

Indexes: subscriptionId, retellAgentId.

Relations: subscription, versions (relation AgentVersions), latestVersion (relation LatestVersion), campaignsPreferredForAnalysis (relation CampaignPreferredAnalysisAgent), callAiAgentAnalysisResults, calls.

The two relations to AiAgentVersion are intentional: versions is the full history, latestVersion is a pointer to the one currently published.

AiAgentVersion

Table ai_agent_versions. Immutable once written.

Field Type Notes

aiAgentId

String @db.Uuid

onDelete: Cascade

subscriptionId

String? @db.Uuid

version

Int

1-based

mainPrompt

String

default "". The call script for a caller agent; the grading criteria for an analysis agent

configJson

Json

default {}. Full Retell IAgentData for callers; model overrides and supplementary config for analysis agents

createdAt

DateTime

No updatedAt — versions are not modified

Unique: (aiAgentId, version). Indexes: aiAgentId, subscriptionId.

Relations: subscription, aiAgent, agentAsLatest, analysisResults, calls.

Because Call.agentVersionId and CallAiAgentAnalysisResult.aiAgentVersionId both reference this table, a call can always be replayed against the exact prompt that was live when it happened.

AgentTestCase

Table agent_test_cases. A saved conversation plus its correct answer, for regression-testing prompt changes.

Field Type Notes

subscriptionId

String @db.Uuid

name, notes

String?

sourceCallId

String? @db.Uuid

The call it was captured from; null for hand-written cases

transcript

String?

Missing transcript ⇒ the case is skipped, not failed

recordingUrl

String?

disposition

String?

Ground truth

isAmazonSeller, aiSuspicionDetected, callScreeningDetected, isDecisionMaker, inVoicemail

Boolean?

Ground truth

userSentiment, nextAction, callSuccessful

String?

Ground truth

Indexes: subscriptionId, sourceCallId. Relation: sourceCall (relation CallTestCases).

A null ground-truth column means "not asserted": the runner reports pass: null and excludes the field from the verdict rather than counting it as a pass. See Regression test cases.

Configs

Table configs. Per-workspace key/value settings.

Field Type Notes

key

String @unique

Globally unique

subscriptionId

String @db.Uuid

value

String

Always a string; callers coerce

Indexes: key, subscriptionId.

Known keys (CONFIG_KEYS in lib/constants.ts):

Key Effect

purchase_new_phone_numbers

Master switch for automatic number purchasing

daily_phone_number_purchase_limit

Cap on purchases per day

hubspot_call_sync_cursor

ISO datetime watermark for calls/hubspot-import; required before the first successful run

Automatic purchasing requires both to be enabled.

key is globally unique rather than unique per workspace, so two workspaces cannot hold different values for the same key. Treat Configs as effectively global until the constraint is changed to (subscriptionId, key).

Accessed through lib/repositories/config-repository.ts. Workspace members can list, create, and edit values on the Settings Config tab (/settings), which calls GET|POST /api/configs and PATCH /api/configs/{id}.