refactor(server): rename Agent exception to Ai; add THREAD_NOT_FOUND / MESSAGE_NOT_FOUND codes (fixes 500s) (#19831)
## Summary - The exception class under `ai-agent/` was serving every AI surface (agent, chat, role, models, generate-text), so `Agent` was a misnomer. Promoted to the `ai/` namespace; renamed `AgentException` → `AiException`, `AgentExceptionCode` → `AiExceptionCode`, and related interceptor / filter / handler / file names accordingly. - Split the single `AGENT_NOT_FOUND` code into entity-specific codes. Chat-thread lookups no longer reuse the agent identifier. - **Fixes Sentry 500s on `GetChatMessages` / `chatThread`.** Every "Thread not found" and "Queued message not found" throw site in ai-chat was previously wired to `AGENT_EXECUTION_FAILED`, which maps to `InternalServerError` (HTTP 500). They now use `THREAD_NOT_FOUND` / `MESSAGE_NOT_FOUND`, both of which map to `NotFoundError` (HTTP 404) in the GraphQL and REST handlers. The underlying cause of *why* clients are asking for threads that no longer resolve for them — per-user chat-thread create events being broadcast workspace-wide — is addressed separately in a follow-up PR. ### Code map - Added: `ai/ai.exception.ts`, `ai/utils/ai-graphql-api-exception-handler.util.ts` (+ spec with new THREAD/MESSAGE cases), `ai/interceptors/ai-graphql-api-exception.interceptor.ts`, `ai/filters/ai-api-exception.filter.ts` - Deleted: `ai/ai-agent/agent.exception.ts`, `ai/ai-agent/utils/agent-graphql-api-exception-handler.util.ts` (+ spec), `ai/ai-agent/interceptors/agent-graphql-api-exception.interceptor.ts`, `ai/ai-agent/filters/agent-api-exception.filter.ts` - Updated: 21 call sites across ai-agent, ai-agent-execution, ai-agent-role, ai-chat, ai-generate-text, ai-models, role, and workspace-migration validators. ## Test plan - [x] `npx nx typecheck twenty-server` - [x] `npx jest ai-graphql-api-exception-handler` (3/3 including new THREAD_NOT_FOUND and MESSAGE_NOT_FOUND cases) - [x] `npx jest agent-role.service` (9/9) - [x] `npx oxlint --type-aware` on all changed files (0 warnings/errors) - [x] `npx prettier --check` on all changed files - [ ] CI
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import { type MessageDescriptor } from '@lingui/core';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { assertUnreachable } from 'twenty-shared/utils';
|
||||
|
||||
import { CustomException } from 'src/utils/custom-exception';
|
||||
|
||||
export enum AiExceptionCode {
|
||||
AGENT_NOT_FOUND = 'AGENT_NOT_FOUND',
|
||||
AGENT_ALREADY_EXISTS = 'AGENT_ALREADY_EXISTS',
|
||||
AGENT_IS_STANDARD = 'AGENT_IS_STANDARD',
|
||||
AGENT_EXECUTION_FAILED = 'AGENT_EXECUTION_FAILED',
|
||||
INVALID_AGENT_INPUT = 'INVALID_AGENT_INPUT',
|
||||
THREAD_NOT_FOUND = 'THREAD_NOT_FOUND',
|
||||
MESSAGE_NOT_FOUND = 'MESSAGE_NOT_FOUND',
|
||||
API_KEY_NOT_CONFIGURED = 'API_KEY_NOT_CONFIGURED',
|
||||
USER_WORKSPACE_ID_NOT_FOUND = 'USER_WORKSPACE_ID_NOT_FOUND',
|
||||
ROLE_NOT_FOUND = 'ROLE_NOT_FOUND',
|
||||
ROLE_CANNOT_BE_ASSIGNED_TO_AGENTS = 'ROLE_CANNOT_BE_ASSIGNED_TO_AGENTS',
|
||||
}
|
||||
|
||||
const getAiExceptionUserFriendlyMessage = (code: AiExceptionCode) => {
|
||||
switch (code) {
|
||||
case AiExceptionCode.AGENT_NOT_FOUND:
|
||||
return msg`Agent not found.`;
|
||||
case AiExceptionCode.AGENT_ALREADY_EXISTS:
|
||||
return msg`An agent with this name already exists.`;
|
||||
case AiExceptionCode.AGENT_IS_STANDARD:
|
||||
return msg`Standard agents cannot be modified.`;
|
||||
case AiExceptionCode.AGENT_EXECUTION_FAILED:
|
||||
return msg`Agent execution failed.`;
|
||||
case AiExceptionCode.INVALID_AGENT_INPUT:
|
||||
return msg`Invalid agent input.`;
|
||||
case AiExceptionCode.THREAD_NOT_FOUND:
|
||||
return msg`Chat thread not found.`;
|
||||
case AiExceptionCode.MESSAGE_NOT_FOUND:
|
||||
return msg`Chat message not found.`;
|
||||
case AiExceptionCode.API_KEY_NOT_CONFIGURED:
|
||||
return msg`API key is not configured.`;
|
||||
case AiExceptionCode.USER_WORKSPACE_ID_NOT_FOUND:
|
||||
return msg`User workspace not found.`;
|
||||
case AiExceptionCode.ROLE_NOT_FOUND:
|
||||
return msg`Role not found.`;
|
||||
case AiExceptionCode.ROLE_CANNOT_BE_ASSIGNED_TO_AGENTS:
|
||||
return msg`This role cannot be assigned to agents.`;
|
||||
default:
|
||||
assertUnreachable(code);
|
||||
}
|
||||
};
|
||||
|
||||
export class AiException extends CustomException<AiExceptionCode> {
|
||||
constructor(
|
||||
message: string,
|
||||
code: AiExceptionCode,
|
||||
{ userFriendlyMessage }: { userFriendlyMessage?: MessageDescriptor } = {},
|
||||
) {
|
||||
super(message, code, {
|
||||
userFriendlyMessage:
|
||||
userFriendlyMessage ?? getAiExceptionUserFriendlyMessage(code),
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user