refactor: standardize AI acronym to Ai (PascalCase) across internal identifiers (#19837)
## Summary
The "AI" acronym was rendered inconsistently across the codebase. The
backend AI module had settled on PascalCase `Ai` (`AiAgentModule`,
`AiBillingService`, `AiChatModule`, `AiModelRegistryService`, etc.),
while frontend components, several DTOs, a few types, and shared
identifiers still used all-caps `AI` (`AIChatTab`,
`AISystemPromptPreviewDTO`, `SettingsPath.AIPrompts`, ...). CLAUDE.md
specifies PascalCase for classes; this PR normalizes everything internal
to `Ai`.
**This is a pure internal rename.** The GraphQL schema is untouched —
`@ObjectType` decorator string arguments, resolver method names (which
become Query/Mutation field names), gql template contents, and the
`generated-metadata/graphql.ts` file are preserved verbatim. The only
visible change is TypeScript identifiers and file names.
## Also folded in (adjacent cleanups)
- **`AgentModelConfigService` → `AiModelConfigService`**. Lives in
`ai-models/` and is used by multiple AI code paths, not just the Agent
entity. The "Agent" prefix was misleading.
- **`generate-text-input.dto.ts` → `generate-text.input.ts`**. The
`ai-agent/dtos/` folder already uses `<entity>.input.ts` convention for
Input classes (`create-agent.input.ts` etc.); the old path mixed
`.dto.ts` file extension with a class that has no DTO suffix. File
rename only; class stays `GenerateTextInput`.
- **Removed stale TODO** in `ai-model-config.type.ts` that asked for the
`AiModelConfig` rename that this PR performs.
## Rename methodology
Bulk rename via perl with anchored regex
`(?<!['"])(?<![A-Z.])AI([A-Z])(?=[a-z])/Ai$1/g`:
- **Lookbehind for non-uppercase** skips adjacent acronyms (`MOSAIC`,
`OIDCSSO`) and leaves `AIRBNB_ID` alone.
- **Lookbehind for non-quote** protects most string literals.
- **Lookahead for lowercase** restricts matches to PascalCase
identifiers (`AIChatTab`), leaving SCREAMING_SNAKE constants untouched.
Strict file-scope exclusions: `generated-metadata/**`, `generated/**`,
`locales/**`, `migrations/**`, `illustrations/**`, `halftone/**`, and
the two gql template files (`queries/getAISystemPromptPreview.ts`,
`mutations/uploadAIChatFile.ts`).
Post-rename reverts for identifiers where the regex was too eager:
- Backend resolver method names kept: `getAISystemPromptPreview`,
`uploadAIChatFile` (they are GraphQL field names).
- `@ObjectType('AdminAIModels')` / `('AISystemPromptPreview')` /
`('AISystemPromptSection')` kept as-is.
- Backend classes `ClientAIModelConfig` / `AdminAIModelConfig` kept
as-is (they use `@ObjectType()` with no argument, so the class name IS
the schema name).
- External-library symbols restored: `OpenAIProvider`,
`createOpenAICompatible`, `vercelAIIntegration`.
File renames use a two-step rename to work on macOS case-insensitive
filesystems: `git mv X.tsx X.tsx.tmp && git mv X.tsx.tmp renamed.tsx`.
## Diff audit
- 0 changes to migrations
- 0 changes to locale `.po` / `.ts` files
- 0 changes to `generated-metadata/graphql.ts`
- 0 changes to website illustration files (base64 blobs preserved)
- 0 renames inside user-facing translation strings (`t\`…\``,
`msg\`…\``, `<Trans>…</Trans>`)
## Test plan
- [x] `npx nx typecheck twenty-server` — PASS
- [x] `npx nx typecheck twenty-front` — PASS
- [x] `npx jest ai-model admin agent-role` — 79/79 PASS
- [x] `npx oxlint --type-aware` on 118 changed files — 0 errors
- [x] `npx prettier --check` on 118 changed files — clean
- [ ] CI
This commit is contained in:
+10
-10
@@ -10,8 +10,8 @@ import { agentChatInputState } from '@/ai/states/agentChatInputState';
|
||||
import { agentChatThreadsLoadingState } from '@/ai/states/agentChatThreadsLoadingState';
|
||||
import { agentChatThreadsSelector } from '@/ai/states/agentChatThreadsSelector';
|
||||
import { agentChatUsageComponentFamilyState } from '@/ai/states/agentChatUsageComponentFamilyState';
|
||||
import { currentAIChatThreadState } from '@/ai/states/currentAIChatThreadState';
|
||||
import { currentAIChatThreadTitleComponentFamilyState } from '@/ai/states/currentAIChatThreadTitleComponentFamilyState';
|
||||
import { currentAiChatThreadState } from '@/ai/states/currentAiChatThreadState';
|
||||
import { currentAiChatThreadTitleComponentFamilyState } from '@/ai/states/currentAiChatThreadTitleComponentFamilyState';
|
||||
import { hasInitializedAgentChatThreadsState } from '@/ai/states/hasInitializedAgentChatThreadsState';
|
||||
import { hasTriggeredCreateForDraftState } from '@/ai/states/hasTriggeredCreateForDraftState';
|
||||
import { useUpdateMetadataStoreDraft } from '@/metadata-store/hooks/useUpdateMetadataStoreDraft';
|
||||
@@ -35,14 +35,14 @@ export const AgentChatThreadInitializationEffect = () => {
|
||||
PermissionFlagType.AI_SETTINGS,
|
||||
);
|
||||
|
||||
const currentAIChatThread = useAtomStateValue(currentAIChatThreadState);
|
||||
const setCurrentAIChatThread = useSetAtomState(currentAIChatThreadState);
|
||||
const currentAiChatThread = useAtomStateValue(currentAiChatThreadState);
|
||||
const setCurrentAiChatThread = useSetAtomState(currentAiChatThreadState);
|
||||
const setAgentChatInput = useSetAtomState(agentChatInputState);
|
||||
const setAgentChatThreadsLoading = useSetAtomState(
|
||||
agentChatThreadsLoadingState,
|
||||
);
|
||||
const threadTitleFamilyCallback = useAtomComponentFamilyStateCallbackState(
|
||||
currentAIChatThreadTitleComponentFamilyState,
|
||||
currentAiChatThreadTitleComponentFamilyState,
|
||||
);
|
||||
const agentChatUsageFamilyCallback = useAtomComponentFamilyStateCallbackState(
|
||||
agentChatUsageComponentFamilyState,
|
||||
@@ -93,7 +93,7 @@ export const AgentChatThreadInitializationEffect = () => {
|
||||
useEffect(() => {
|
||||
if (
|
||||
hasInitializedAgentChatThreads ||
|
||||
(currentAIChatThread !== null && isValidUuid(currentAIChatThread))
|
||||
(currentAiChatThread !== null && isValidUuid(currentAiChatThread))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@@ -114,7 +114,7 @@ export const AgentChatThreadInitializationEffect = () => {
|
||||
const draftForThread =
|
||||
store.get(agentChatDraftsByThreadIdState.atom)[firstThread.id] ?? '';
|
||||
|
||||
setCurrentAIChatThread(firstThread.id);
|
||||
setCurrentAiChatThread(firstThread.id);
|
||||
setAgentChatInput(draftForThread);
|
||||
|
||||
const firstThreadFamilyKey = { threadId: firstThread.id };
|
||||
@@ -144,7 +144,7 @@ export const AgentChatThreadInitializationEffect = () => {
|
||||
);
|
||||
} else {
|
||||
store.set(hasTriggeredCreateForDraftState.atom, false);
|
||||
setCurrentAIChatThread(AGENT_CHAT_NEW_THREAD_DRAFT_KEY);
|
||||
setCurrentAiChatThread(AGENT_CHAT_NEW_THREAD_DRAFT_KEY);
|
||||
setAgentChatInput(
|
||||
store.get(agentChatDraftsByThreadIdState.atom)[
|
||||
AGENT_CHAT_NEW_THREAD_DRAFT_KEY
|
||||
@@ -153,12 +153,12 @@ export const AgentChatThreadInitializationEffect = () => {
|
||||
}
|
||||
}, [
|
||||
agentChatThreads,
|
||||
currentAIChatThread,
|
||||
currentAiChatThread,
|
||||
hasAiSettingsPermission,
|
||||
hasInitializedAgentChatThreads,
|
||||
setHasInitializedAgentChatThreads,
|
||||
storeEntry.status,
|
||||
setCurrentAIChatThread,
|
||||
setCurrentAiChatThread,
|
||||
setAgentChatInput,
|
||||
store,
|
||||
threadTitleFamilyCallback,
|
||||
|
||||
Reference in New Issue
Block a user