Fix: AI Agent tool errors and relation field handling (#15668)
### Problems Fixed
1. **Tool execution errors broke conversations**
- Failed tool executions showed "Processing..." indefinitely instead of
error messages
- Tool errors with `input: null` caused subsequent messages to fail with
`Missing required parameter: 'input[X].arguments'`
2. **Relation fields not saved in AI Agent**
- AI Agent couldn't save relation fields (e.g., `companyId`) when
creating/upserting records
- Join column names weren't recognized during field validation
### Solutions
**Tool Error Handling:**
- Display error messages in UI with expandable error details
- Ensure tool parts always have valid `input` field (`input:
part.toolInput ?? {}`)
- Refactored `ToolStepRenderer` to accept complete `toolPart` object
**Relation Field Support:**
- Updated field validation in `create-record.service.ts` and
`upsert-record.service.ts`
- Check both `fieldIdByName` and `fieldIdByJoinColumnName` mappings
### Changes
- `packages/twenty-front/src/modules/ai/`
- `ToolStepRenderer.tsx` - Error state handling
- `AIChatAssistantMessageRenderer.tsx` - Pass complete toolPart
- `mapDBPartToUIMessagePart.ts` - Prevent null tool input
- `packages/twenty-server/src/engine/core-modules/record-crud/services/`
- `create-record.service.ts` - Add join column validation
- `upsert-record.service.ts` - Add join column validation
This commit is contained in:
+6
-2
@@ -73,8 +73,12 @@ export class CreateRecordService {
|
||||
});
|
||||
|
||||
const validObjectRecord = Object.fromEntries(
|
||||
Object.entries(objectRecord).filter(([key]) =>
|
||||
isDefined(objectMetadataItemWithFieldsMaps.fieldIdByName[key]),
|
||||
Object.entries(objectRecord).filter(
|
||||
([key]) =>
|
||||
isDefined(objectMetadataItemWithFieldsMaps.fieldIdByName[key]) ||
|
||||
isDefined(
|
||||
objectMetadataItemWithFieldsMaps.fieldIdByJoinColumnName[key],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
+6
-2
@@ -92,9 +92,13 @@ export class UpsertRecordService {
|
||||
});
|
||||
|
||||
const uniqueFieldsToUpdate = fieldsToUpdateArray
|
||||
.map((field) => objectMetadataItemWithFieldsMaps.fieldIdByName[field])
|
||||
.map(
|
||||
(field) =>
|
||||
objectMetadataItemWithFieldsMaps.fieldIdByName[field] ||
|
||||
objectMetadataItemWithFieldsMaps.fieldIdByJoinColumnName[field],
|
||||
)
|
||||
.map((fieldId) => objectMetadataItemWithFieldsMaps.fieldsById[fieldId])
|
||||
.filter((field) => field.isUnique || field.name === 'id');
|
||||
.filter((field) => field && (field.isUnique || field.name === 'id'));
|
||||
|
||||
const conflictPathsUniqueFieldsToUpdate = uniqueFieldsToUpdate.flatMap(
|
||||
(field) => {
|
||||
|
||||
Reference in New Issue
Block a user