Restructure agent chat messages with parts-based architecture (#14749)

Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
Abdul Rahman
2025-09-29 17:01:55 +05:30
committed by GitHub
parent 84cbd8e092
commit 2685f4a5b9
69 changed files with 1200 additions and 1539 deletions
@@ -3,6 +3,7 @@ import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
import { Command } from 'nest-commander';
import { type ViewFilterOperand as SharedViewFilterOperand } from 'twenty-shared/types';
import { DataSource, In, Repository, type QueryRunner } from 'typeorm';
import { type QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
import {
ActiveOrSuspendedWorkspacesMigrationCommandRunner,
@@ -477,7 +478,7 @@ export class MigrateViewsToCoreCommand extends ActiveOrSuspendedWorkspacesMigrat
viewName = 'All {objectLabelPlural}';
}
const coreView: Partial<ViewEntity> = {
const coreView: QueryDeepPartialEntity<ViewEntity> = {
id: workspaceView.id,
name: viewName,
objectMetadataId: workspaceView.objectMetadataId,
@@ -517,7 +518,7 @@ export class MigrateViewsToCoreCommand extends ActiveOrSuspendedWorkspacesMigrat
queryRunner: QueryRunner,
): Promise<void> {
for (const field of workspaceViewFields) {
const coreViewField: Partial<ViewFieldEntity> = {
const coreViewField: QueryDeepPartialEntity<ViewFieldEntity> = {
id: field.id,
fieldMetadataId: field.fieldMetadataId,
viewId: field.viewId,
@@ -549,7 +550,7 @@ export class MigrateViewsToCoreCommand extends ActiveOrSuspendedWorkspacesMigrat
continue;
}
const coreViewFilter: Partial<ViewFilterEntity> = {
const coreViewFilter: QueryDeepPartialEntity<ViewFilterEntity> = {
id: filter.id,
fieldMetadataId: filter.fieldMetadataId,
viewId: filter.viewId,
@@ -586,7 +587,7 @@ export class MigrateViewsToCoreCommand extends ActiveOrSuspendedWorkspacesMigrat
const direction = sort.direction.toUpperCase() as ViewSortDirection;
const coreViewSort: Partial<ViewSortEntity> = {
const coreViewSort: QueryDeepPartialEntity<ViewSortEntity> = {
id: sort.id,
fieldMetadataId: sort.fieldMetadataId,
viewId: sort.viewId,
@@ -616,7 +617,7 @@ export class MigrateViewsToCoreCommand extends ActiveOrSuspendedWorkspacesMigrat
continue;
}
const coreViewGroup: Partial<ViewGroupEntity> = {
const coreViewGroup: QueryDeepPartialEntity<ViewGroupEntity> = {
id: group.id,
fieldMetadataId: group.fieldMetadataId,
viewId: group.viewId,
@@ -644,20 +645,21 @@ export class MigrateViewsToCoreCommand extends ActiveOrSuspendedWorkspacesMigrat
(a, b) =>
new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(),
)) {
const coreViewFilterGroup: Partial<ViewFilterGroupEntity> = {
id: filterGroup.id,
viewId: filterGroup.viewId,
logicalOperator:
filterGroup.logicalOperator as ViewFilterGroupLogicalOperator,
parentViewFilterGroupId: filterGroup.parentViewFilterGroupId,
positionInViewFilterGroup: filterGroup.positionInViewFilterGroup,
workspaceId,
createdAt: new Date(filterGroup.createdAt),
updatedAt: new Date(filterGroup.updatedAt),
deletedAt: filterGroup.deletedAt
? new Date(filterGroup.deletedAt)
: null,
};
const coreViewFilterGroup: QueryDeepPartialEntity<ViewFilterGroupEntity> =
{
id: filterGroup.id,
viewId: filterGroup.viewId,
logicalOperator:
filterGroup.logicalOperator as ViewFilterGroupLogicalOperator,
parentViewFilterGroupId: filterGroup.parentViewFilterGroupId,
positionInViewFilterGroup: filterGroup.positionInViewFilterGroup,
workspaceId,
createdAt: new Date(filterGroup.createdAt),
updatedAt: new Date(filterGroup.updatedAt),
deletedAt: filterGroup.deletedAt
? new Date(filterGroup.deletedAt)
: null,
};
const repository = queryRunner.manager.getRepository(
ViewFilterGroupEntity,
@@ -0,0 +1,33 @@
import { type MigrationInterface, type QueryRunner } from 'typeorm';
export class NameOfYourMigration1758767315179 implements MigrationInterface {
name = 'CreateAgentChatMessagePartTableAndRemoveRawContent1758767315179';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "core"."agentChatMessagePart" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "messageId" uuid NOT NULL, "orderIndex" integer NOT NULL, "type" character varying NOT NULL, "textContent" text, "reasoningContent" text, "toolName" character varying, "toolCallId" character varying, "toolInput" jsonb, "toolOutput" jsonb, "state" character varying, "errorMessage" text, "errorDetails" jsonb, "sourceUrlSourceId" character varying, "sourceUrlUrl" character varying, "sourceUrlTitle" character varying, "sourceDocumentSourceId" character varying, "sourceDocumentMediaType" character varying, "sourceDocumentTitle" character varying, "sourceDocumentFilename" character varying, "fileMediaType" character varying, "fileFilename" character varying, "fileUrl" character varying, "providerMetadata" jsonb, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_c28499bb0699730d41e57e1fe23" PRIMARY KEY ("id"))`,
);
await queryRunner.query(
`CREATE INDEX "IDX_5d4b48eeebfa7b23cd2226a874" ON "core"."agentChatMessagePart" ("messageId") `,
);
await queryRunner.query(
`ALTER TABLE "core"."agentChatMessage" DROP COLUMN "rawContent"`,
);
await queryRunner.query(
`ALTER TABLE "core"."agentChatMessagePart" ADD CONSTRAINT "FK_5d4b48eeebfa7b23cd2226a874f" FOREIGN KEY ("messageId") REFERENCES "core"."agentChatMessage"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."agentChatMessagePart" DROP CONSTRAINT "FK_5d4b48eeebfa7b23cd2226a874f"`,
);
await queryRunner.query(
`ALTER TABLE "core"."agentChatMessage" ADD "rawContent" text`,
);
await queryRunner.query(
`DROP INDEX "core"."IDX_5d4b48eeebfa7b23cd2226a874"`,
);
await queryRunner.query(`DROP TABLE "core"."agentChatMessagePart"`);
}
}