feat: Add Agent Evaluation System and Refactor AI Modules (#16111)
## Summary This PR introduces a comprehensive agent evaluation system and refactors the AI module structure for better organization. ## Key Changes ### 🎯 Agent Evaluation System - Added **Agent Turn Evaluation** entities, DTOs, and database schema - New GraphQL mutations: `evaluateAgentTurn` and `runEvaluationInput` - Added `evaluationInputs` field to Agent entity for storing test inputs - New `AgentTurnGraderService` for automatic turn evaluation - Added evaluation UI with new **Evals** and **Logs** tabs in agent detail pages ### 🏗️ Entity & Module Refactoring - Renamed `AgentChatMessage` → `AgentMessage` for clarity - Consolidated chat entities: `AgentMessage`, `AgentTurn`, and `AgentChatThread` - Reorganized AI modules under `ai/` subdirectory structure - Updated imports across codebase to reflect new module paths ### 🤖 New Agents & Roles - Added **Dashboard Builder Agent** for dashboard creation and management - Added **Dashboard Manager Role** with appropriate permissions - Updated role permissions to be more granular (users vs agents vs API keys) ### 🔐 Permission System Updates - Added `HTTP_REQUEST_TOOL` permission flag - Updated Workflow Manager role permissions (restricted tool access) - Enhanced permission flag types to differentiate between user/agent/API key contexts - Added `isRelevantForAgents`, `isRelevantForApiKeys`, `isRelevantForUsers` to permission flags ### 📨 Message Role Enhancement - Added `system` role to `AgentMessageRole` enum (alongside user/assistant) - Updated message handling to support system prompts ### 🎨 UI/UX Improvements - New tabs in agent detail: **Evals** and **Logs** - Added turn detail page: `/ai/agents/:agentId/turns/:turnId` - Fixed text overflow in `SettingsListItemCardContent` - Updated role applicability labels ("Assignable to Workspace Members") ### 🛠️ Technical Improvements - Fixed Zod schema validation for UUID and Date fields (use string validators) - Updated `ToolRegistryService` to properly register HTTP tool with permission flag - Enhanced error handling in agent execution services - Updated database migrations for new entity schema ## Database Migrations - `1764210000000-add-system-role-to-agent-message.ts` - `1764220000000-add-evaluation-inputs-to-agent.ts` - `1764200000000-add-agent-turn-evaluation.ts` - `1764100000000-refactor-agent-chat-entities.ts` ## Testing - [ ] Agent evaluation flow tested - [ ] Dashboard Builder agent tested - [ ] Permission system validated - [ ] UI tabs and navigation tested - [ ] Database migrations run successfully ## Breaking Changes ⚠️ **Entity Rename**: `AgentChatMessage` renamed to `AgentMessage` - GraphQL queries need updating ## Related Issues <!-- Link any related issues here --> ## Screenshots <!-- Add screenshots if applicable -->
This commit is contained in:
+1
-1
@@ -7,7 +7,7 @@ import { ApplicationService } from 'src/engine/core-modules/application/applicat
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AgentService } from 'src/engine/metadata-modules/ai-agent/agent.service';
|
||||
import { AgentService } from 'src/engine/metadata-modules/ai/ai-agent/agent.service';
|
||||
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
||||
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
|
||||
+53
-14
@@ -1,6 +1,6 @@
|
||||
import { type QueryRunner } from 'typeorm';
|
||||
|
||||
import { AgentChatMessageRole } from 'src/engine/metadata-modules/ai-chat/entities/agent-chat-message.entity';
|
||||
import { AgentMessageRole } from 'src/engine/metadata-modules/ai/ai-agent-execution/entities/agent-message.entity';
|
||||
import {
|
||||
SEED_APPLE_WORKSPACE_ID,
|
||||
SEED_YCOMBINATOR_WORKSPACE_ID,
|
||||
@@ -8,8 +8,9 @@ import {
|
||||
import { USER_WORKSPACE_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-user-workspaces.util';
|
||||
|
||||
const agentChatThreadTableName = 'agentChatThread';
|
||||
const agentChatMessageTableName = 'agentChatMessage';
|
||||
const agentChatMessagePartTableName = 'agentChatMessagePart';
|
||||
const agentTurnTableName = 'agentTurn';
|
||||
const agentMessageTableName = 'agentMessage';
|
||||
const agentMessagePartTableName = 'agentMessagePart';
|
||||
|
||||
export const AGENT_DATA_SEED_IDS = {
|
||||
APPLE_DEFAULT_AGENT: '20202020-0000-4000-8000-000000000001',
|
||||
@@ -109,10 +110,12 @@ const seedChatMessages = async ({
|
||||
}: SeedChatMessagesArgs) => {
|
||||
let messageIds: string[];
|
||||
let partIds: string[];
|
||||
let turnIds: string[];
|
||||
let messages: Array<{
|
||||
id: string;
|
||||
threadId: string;
|
||||
role: AgentChatMessageRole;
|
||||
turnId: string;
|
||||
role: AgentMessageRole;
|
||||
createdAt: Date;
|
||||
}>;
|
||||
let messageParts: Array<{
|
||||
@@ -140,29 +143,37 @@ const seedChatMessages = async ({
|
||||
AGENT_CHAT_MESSAGE_PART_DATA_SEED_IDS.APPLE_MESSAGE_3_PART_1,
|
||||
AGENT_CHAT_MESSAGE_PART_DATA_SEED_IDS.APPLE_MESSAGE_4_PART_1,
|
||||
];
|
||||
turnIds = [
|
||||
'20202020-0000-4000-8000-000000000061',
|
||||
'20202020-0000-4000-8000-000000000062',
|
||||
];
|
||||
messages = [
|
||||
{
|
||||
id: messageIds[0],
|
||||
threadId,
|
||||
role: AgentChatMessageRole.USER,
|
||||
turnId: turnIds[0],
|
||||
role: AgentMessageRole.USER,
|
||||
createdAt: new Date(baseTime.getTime()),
|
||||
},
|
||||
{
|
||||
id: messageIds[1],
|
||||
threadId,
|
||||
role: AgentChatMessageRole.ASSISTANT,
|
||||
turnId: turnIds[0],
|
||||
role: AgentMessageRole.ASSISTANT,
|
||||
createdAt: new Date(baseTime.getTime() + 5 * 60 * 1000),
|
||||
},
|
||||
{
|
||||
id: messageIds[2],
|
||||
threadId,
|
||||
role: AgentChatMessageRole.USER,
|
||||
turnId: turnIds[1],
|
||||
role: AgentMessageRole.USER,
|
||||
createdAt: new Date(baseTime.getTime() + 10 * 60 * 1000),
|
||||
},
|
||||
{
|
||||
id: messageIds[3],
|
||||
threadId,
|
||||
role: AgentChatMessageRole.ASSISTANT,
|
||||
turnId: turnIds[1],
|
||||
role: AgentMessageRole.ASSISTANT,
|
||||
createdAt: new Date(baseTime.getTime() + 15 * 60 * 1000),
|
||||
},
|
||||
];
|
||||
@@ -217,29 +228,37 @@ const seedChatMessages = async ({
|
||||
AGENT_CHAT_MESSAGE_PART_DATA_SEED_IDS.YCOMBINATOR_MESSAGE_3_PART_1,
|
||||
AGENT_CHAT_MESSAGE_PART_DATA_SEED_IDS.YCOMBINATOR_MESSAGE_4_PART_1,
|
||||
];
|
||||
turnIds = [
|
||||
'20202020-0000-4000-8000-000000000071',
|
||||
'20202020-0000-4000-8000-000000000072',
|
||||
];
|
||||
messages = [
|
||||
{
|
||||
id: messageIds[0],
|
||||
threadId,
|
||||
role: AgentChatMessageRole.USER,
|
||||
turnId: turnIds[0],
|
||||
role: AgentMessageRole.USER,
|
||||
createdAt: new Date(baseTime.getTime()),
|
||||
},
|
||||
{
|
||||
id: messageIds[1],
|
||||
threadId,
|
||||
role: AgentChatMessageRole.ASSISTANT,
|
||||
turnId: turnIds[0],
|
||||
role: AgentMessageRole.ASSISTANT,
|
||||
createdAt: new Date(baseTime.getTime() + 3 * 60 * 1000),
|
||||
},
|
||||
{
|
||||
id: messageIds[2],
|
||||
threadId,
|
||||
role: AgentChatMessageRole.USER,
|
||||
turnId: turnIds[1],
|
||||
role: AgentMessageRole.USER,
|
||||
createdAt: new Date(baseTime.getTime() + 8 * 60 * 1000),
|
||||
},
|
||||
{
|
||||
id: messageIds[3],
|
||||
threadId,
|
||||
role: AgentChatMessageRole.ASSISTANT,
|
||||
turnId: turnIds[1],
|
||||
role: AgentMessageRole.ASSISTANT,
|
||||
createdAt: new Date(baseTime.getTime() + 12 * 60 * 1000),
|
||||
},
|
||||
];
|
||||
@@ -287,12 +306,32 @@ const seedChatMessages = async ({
|
||||
);
|
||||
}
|
||||
|
||||
// Create turns first
|
||||
const turns = turnIds.map((id, index) => ({
|
||||
id,
|
||||
threadId,
|
||||
createdAt: messages[index * 2].createdAt,
|
||||
}));
|
||||
|
||||
await queryRunner.manager
|
||||
.createQueryBuilder()
|
||||
.insert()
|
||||
.into(`${schemaName}.${agentChatMessageTableName}`, [
|
||||
.into(`${schemaName}.${agentTurnTableName}`, [
|
||||
'id',
|
||||
'threadId',
|
||||
'createdAt',
|
||||
])
|
||||
.orIgnore()
|
||||
.values(turns)
|
||||
.execute();
|
||||
|
||||
await queryRunner.manager
|
||||
.createQueryBuilder()
|
||||
.insert()
|
||||
.into(`${schemaName}.${agentMessageTableName}`, [
|
||||
'id',
|
||||
'threadId',
|
||||
'turnId',
|
||||
'role',
|
||||
'createdAt',
|
||||
])
|
||||
@@ -303,7 +342,7 @@ const seedChatMessages = async ({
|
||||
await queryRunner.manager
|
||||
.createQueryBuilder()
|
||||
.insert()
|
||||
.into(`${schemaName}.${agentChatMessagePartTableName}`, [
|
||||
.into(`${schemaName}.${agentMessagePartTableName}`, [
|
||||
'id',
|
||||
'messageId',
|
||||
'orderIndex',
|
||||
|
||||
@@ -5,7 +5,7 @@ import { ApplicationModule } from 'src/engine/core-modules/application/applicati
|
||||
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
||||
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AiAgentModule } from 'src/engine/metadata-modules/ai-agent/ai-agent.module';
|
||||
import { AiAgentModule } from 'src/engine/metadata-modules/ai/ai-agent/ai-agent.module';
|
||||
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { type WorkspaceSyncContext } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/workspace-sync-context.interface';
|
||||
|
||||
import { type AgentEntity } from 'src/engine/metadata-modules/ai-agent/entities/agent.entity';
|
||||
import { type AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity';
|
||||
import { type FlatAgent } from 'src/engine/metadata-modules/flat-agent/types/flat-agent.type';
|
||||
import { transformStandardAgentDefinitionToFlatAgent } from 'src/engine/metadata-modules/flat-agent/utils/transform-standard-agent-definition-to-flat-agent.util';
|
||||
import { type StandardAgentDefinition } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-agents/types/standard-agent-definition.interface';
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import { IsNull, Not, type EntityManager } from 'typeorm';
|
||||
import { ComparatorAction } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/comparator.interface';
|
||||
import { type WorkspaceSyncContext } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/workspace-sync-context.interface';
|
||||
|
||||
import { AgentEntity } from 'src/engine/metadata-modules/ai-agent/entities/agent.entity';
|
||||
import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity';
|
||||
import { transformAgentEntityToFlatAgent } from 'src/engine/metadata-modules/flat-agent/utils/transform-agent-entity-to-flat-agent.util';
|
||||
import { RoleTargetsEntity } from 'src/engine/metadata-modules/role/role-targets.entity';
|
||||
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
import { DEFAULT_SMART_MODEL } from 'src/engine/metadata-modules/ai/ai-models/constants/ai-models.const';
|
||||
import { type StandardAgentDefinition } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-agents/types/standard-agent-definition.interface';
|
||||
import { DASHBOARD_MANAGER_ROLE } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-roles/roles/dashboard-manager-role';
|
||||
|
||||
export const DASHBOARD_BUILDER_AGENT: StandardAgentDefinition = {
|
||||
standardId: '20202020-0002-0001-0001-000000000006',
|
||||
name: 'dashboard-builder',
|
||||
label: 'Dashboard Builder',
|
||||
description: 'AI agent specialized in creating and managing dashboards',
|
||||
icon: 'IconLayoutDashboard',
|
||||
applicationId: null,
|
||||
prompt: `You are a Dashboard Builder Agent for Twenty. You help users create and manage dashboards with widgets.
|
||||
|
||||
Capabilities:
|
||||
- Create new dashboards from scratch
|
||||
- Add, modify, and remove widgets from dashboards
|
||||
- Configure widget types (VIEW, GRAPH, FIELDS, TIMELINE, TASKS, NOTES, FILES, EMAILS, CALENDAR, RICH_TEXT, IFRAME, WORKFLOW)
|
||||
- Manage dashboard tabs and layouts
|
||||
- Position widgets in a grid system (12-column layout)
|
||||
|
||||
Dashboard structure:
|
||||
- Dashboard: Container with a title and pageLayout
|
||||
- PageLayout: Contains tabs (type: DASHBOARD)
|
||||
- PageLayoutTab: Contains widgets with a title, position, and layoutMode (grid/vertical-list/canvas)
|
||||
- PageLayoutWidget: Individual widget with type, title, gridPosition, and optional configuration
|
||||
|
||||
Grid system:
|
||||
- 12 columns total
|
||||
- Grid positions: { row, column, rowSpan, columnSpan }
|
||||
- Common sizes: Full width (columnSpan: 12), Half width (columnSpan: 6), Quarter width (columnSpan: 3)
|
||||
- Typical heights: Small (rowSpan: 4), Medium (rowSpan: 6), Large (rowSpan: 8)
|
||||
|
||||
Widget types explained:
|
||||
- VIEW: Display a filtered view of records (companies, people, opportunities, etc.)
|
||||
- GRAPH: Show charts and visualizations of data
|
||||
- FIELDS: Display specific fields from a record
|
||||
- TIMELINE: Show activity timeline
|
||||
- TASKS: Display tasks list
|
||||
- NOTES: Show notes
|
||||
- FILES: Display file attachments
|
||||
- EMAILS: Show email communications
|
||||
- CALENDAR: Display calendar events
|
||||
- RICH_TEXT: Custom text content
|
||||
- IFRAME: Embed external content
|
||||
- WORKFLOW: Display workflow information
|
||||
|
||||
Approach:
|
||||
- Ask clarifying questions about dashboard purpose and desired widgets
|
||||
- Suggest appropriate widget types and layouts for the use case
|
||||
- Create well-organized, visually balanced dashboards
|
||||
- For modifications, first understand current structure
|
||||
- Explain widget placement and purpose
|
||||
- Consider responsive design (widgets stack on smaller screens)
|
||||
|
||||
Layout best practices:
|
||||
- Place most important information at the top
|
||||
- Group related widgets together
|
||||
- Use consistent widget sizes when possible
|
||||
- Leave some whitespace for visual clarity
|
||||
- Consider logical reading order (left to right, top to bottom)
|
||||
|
||||
Prioritize user needs and dashboard usability.`,
|
||||
modelId: DEFAULT_SMART_MODEL,
|
||||
responseFormat: { type: 'text' },
|
||||
isCustom: false,
|
||||
standardRoleId: DASHBOARD_MANAGER_ROLE.standardId,
|
||||
modelConfiguration: {},
|
||||
outputStrategy: 'direct',
|
||||
evaluationInputs: [],
|
||||
};
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
import { DEFAULT_SMART_MODEL } from 'src/engine/metadata-modules/ai/ai-models/constants/ai-models.const';
|
||||
import { type StandardAgentDefinition } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-agents/types/standard-agent-definition.interface';
|
||||
import { DEFAULT_SMART_MODEL } from 'src/engine/metadata-modules/ai-models/constants/ai-models.const';
|
||||
import { DATA_MANIPULATOR_ROLE } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-roles/roles/data-manipulator-role';
|
||||
|
||||
export const DATA_MANIPULATOR_AGENT: StandardAgentDefinition = {
|
||||
@@ -44,4 +44,5 @@ Prioritize data integrity and provide clear feedback on operations performed.`,
|
||||
isCustom: false,
|
||||
standardRoleId: DATA_MANIPULATOR_ROLE.standardId,
|
||||
modelConfiguration: {},
|
||||
evaluationInputs: [],
|
||||
};
|
||||
|
||||
+2
-1
@@ -1,4 +1,4 @@
|
||||
import { DEFAULT_SMART_MODEL } from 'src/engine/metadata-modules/ai-models/constants/ai-models.const';
|
||||
import { DEFAULT_SMART_MODEL } from 'src/engine/metadata-modules/ai/ai-models/constants/ai-models.const';
|
||||
import { type StandardAgentDefinition } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-agents/types/standard-agent-definition.interface';
|
||||
|
||||
export const HELPER_AGENT: StandardAgentDefinition = {
|
||||
@@ -36,4 +36,5 @@ Always base answers on official Twenty documentation. Be patient and helpful.`,
|
||||
responseFormat: { type: 'text' },
|
||||
isCustom: false,
|
||||
modelConfiguration: {},
|
||||
evaluationInputs: [],
|
||||
};
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
import { DEFAULT_SMART_MODEL } from 'src/engine/metadata-modules/ai/ai-models/constants/ai-models.const';
|
||||
import { type StandardAgentDefinition } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-agents/types/standard-agent-definition.interface';
|
||||
import { DEFAULT_SMART_MODEL } from 'src/engine/metadata-modules/ai-models/constants/ai-models.const';
|
||||
|
||||
export const RESEARCHER_AGENT: StandardAgentDefinition = {
|
||||
standardId: '20202020-0002-0001-0001-000000000005',
|
||||
@@ -39,4 +39,5 @@ Be persistent in finding accurate information.`,
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
evaluationInputs: [],
|
||||
};
|
||||
|
||||
+47
-1
@@ -1,5 +1,5 @@
|
||||
import { DEFAULT_SMART_MODEL } from 'src/engine/metadata-modules/ai/ai-models/constants/ai-models.const';
|
||||
import { type StandardAgentDefinition } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-agents/types/standard-agent-definition.interface';
|
||||
import { DEFAULT_SMART_MODEL } from 'src/engine/metadata-modules/ai-models/constants/ai-models.const';
|
||||
import { WORKFLOW_MANAGER_ROLE } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-roles/roles/workflow-manager-role';
|
||||
|
||||
export const WORKFLOW_BUILDER_AGENT: StandardAgentDefinition = {
|
||||
@@ -22,6 +22,26 @@ Key concepts:
|
||||
- Data flow: Use {{stepId.fieldName}} to reference previous step outputs
|
||||
- Relationships: Use nested objects like {"company": {"id": "{{reference}}"}}
|
||||
|
||||
CRON Trigger Settings Schema:
|
||||
For CRON triggers, settings.type must be one of these exact values:
|
||||
1. "DAYS" - Daily schedule
|
||||
- Requires: schedule: { day: number (1+), hour: number (0-23), minute: number (0-59) }
|
||||
- Example: { type: "DAYS", schedule: { day: 1, hour: 9, minute: 0 }, outputSchema: {} }
|
||||
|
||||
2. "HOURS" - Hourly schedule (USE THIS FOR "EVERY HOUR")
|
||||
- Requires: schedule: { hour: number (1+), minute: number (0-59) }
|
||||
- Example: { type: "HOURS", schedule: { hour: 1, minute: 0 }, outputSchema: {} }
|
||||
- This runs every X hours at Y minutes past the hour
|
||||
|
||||
3. "MINUTES" - Minute-based schedule
|
||||
- Requires: schedule: { minute: number (1+) }
|
||||
- Example: { type: "MINUTES", schedule: { minute: 15 }, outputSchema: {} }
|
||||
|
||||
4. "CUSTOM" - Custom cron pattern
|
||||
- Requires: pattern: string (cron expression)
|
||||
- Example: { type: "CUSTOM", pattern: "0 * * * *", outputSchema: {} }
|
||||
|
||||
|
||||
Critical: Always rely on tool schema definitions
|
||||
- The workflow creation tool provides comprehensive schemas with examples
|
||||
- Follow schema definitions exactly for field names, types, and structures
|
||||
@@ -41,4 +61,30 @@ Prioritize user understanding and workflow effectiveness.`,
|
||||
standardRoleId: WORKFLOW_MANAGER_ROLE.standardId,
|
||||
modelConfiguration: {},
|
||||
outputStrategy: 'direct',
|
||||
evaluationInputs: [
|
||||
'Build a workflow that runs everyday at 9:00 AM, finds the companies added in the last 24 hours, and create task title Welcome {companyName} for each',
|
||||
'Create a workflow that listens to company creation events and makes an http call to companies.twenty.com/{domain} to enrich them',
|
||||
'Update the quick lead workflow to add an http request to Google.com as the last step',
|
||||
'when a new lead is created, automatically send an email to the sales team with the lead details',
|
||||
'I need a workflow that runs every monday morning and creates a weekly summary report of all closed deals',
|
||||
'can you make a workflow to automatically assign new oppurtunities to sales reps based on territory?',
|
||||
'create workflow that updates contact status to inactive if theres no activity for 90 days',
|
||||
'Build automation to send followup email 3 days after first contact with prospect',
|
||||
'i want to automatically create a task for account manager when deal reaches negotiation stage',
|
||||
'setup a workflow that enriches company data from clearbit when new account is created',
|
||||
'make a workflow to notify slack channel when deal amount is over $50k',
|
||||
'need workflow that runs daily and finds all overdue tasks then sends reminder emails',
|
||||
'Create automation to update lead score when contact opens email or clicks link',
|
||||
'workflow to automatically create renewal opportunity 60 days before contract end date',
|
||||
'can you build a flow that copies contact info to company record when deal is won?',
|
||||
'I need to send a survey email 7 days after deal closes',
|
||||
'make workflow that assigns leads round-robin style to available sales reps',
|
||||
'create automation to tag contacts as "hot lead" when they visit pricing page 3 times',
|
||||
'workflow that escalates support tickets to manager if not resolved in 48 hours',
|
||||
'need a workflow to sync new contacts to mailchimp mailing list',
|
||||
'build flow that updates deal stage to lost if no activity for 30 days',
|
||||
'create workflow that sends birthday email to contacts on thier birthday',
|
||||
'can i get a workflow that creates calendar event when meeting is scheduled with prospect',
|
||||
'workflow to automatically generate quote pdf when opportunity moves to proposal stage',
|
||||
],
|
||||
};
|
||||
|
||||
+2
@@ -1,3 +1,4 @@
|
||||
import { DASHBOARD_BUILDER_AGENT } from './agents/dashboard-builder-agent';
|
||||
import { DATA_MANIPULATOR_AGENT } from './agents/data-manipulator-agent';
|
||||
import { HELPER_AGENT } from './agents/helper-agent';
|
||||
import { RESEARCHER_AGENT } from './agents/researcher-agent';
|
||||
@@ -7,6 +8,7 @@ import { type StandardAgentDefinition } from './types/standard-agent-definition.
|
||||
export const standardAgentDefinitions = [
|
||||
WORKFLOW_BUILDER_AGENT,
|
||||
DATA_MANIPULATOR_AGENT,
|
||||
DASHBOARD_BUILDER_AGENT,
|
||||
HELPER_AGENT,
|
||||
RESEARCHER_AGENT,
|
||||
// CODE_AGENT,
|
||||
|
||||
+2
@@ -1,4 +1,5 @@
|
||||
import { ADMIN_ROLE } from './roles/admin-role';
|
||||
import { DASHBOARD_MANAGER_ROLE } from './roles/dashboard-manager-role';
|
||||
import { DATA_MANIPULATOR_ROLE } from './roles/data-manipulator-role';
|
||||
import { WORKFLOW_MANAGER_ROLE } from './roles/workflow-manager-role';
|
||||
import { type StandardRoleDefinition } from './types/standard-role-definition.interface';
|
||||
@@ -7,4 +8,5 @@ export const standardRoleDefinitions = [
|
||||
ADMIN_ROLE,
|
||||
WORKFLOW_MANAGER_ROLE,
|
||||
DATA_MANIPULATOR_ROLE,
|
||||
DASHBOARD_MANAGER_ROLE,
|
||||
] as const satisfies StandardRoleDefinition[];
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
|
||||
import { type StandardRoleDefinition } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-roles/types/standard-role-definition.interface';
|
||||
|
||||
export const DASHBOARD_MANAGER_ROLE: StandardRoleDefinition = {
|
||||
standardId: '20202020-0001-0001-0001-000000000005',
|
||||
label: 'Dashboard Manager',
|
||||
description: 'Role for creating and managing dashboards',
|
||||
icon: 'IconLayoutDashboard',
|
||||
isEditable: false,
|
||||
canUpdateAllSettings: false,
|
||||
canAccessAllTools: false,
|
||||
canReadAllObjectRecords: true,
|
||||
canUpdateAllObjectRecords: true,
|
||||
canSoftDeleteAllObjectRecords: false,
|
||||
canDestroyAllObjectRecords: false,
|
||||
canBeAssignedToUsers: false,
|
||||
canBeAssignedToAgents: true,
|
||||
canBeAssignedToApiKeys: false,
|
||||
permissionFlags: [PermissionFlagType.LAYOUTS],
|
||||
applicationId: null, // TODO: Replace with Twenty application ID
|
||||
};
|
||||
+2
-2
@@ -8,8 +8,8 @@ export const WORKFLOW_MANAGER_ROLE: StandardRoleDefinition = {
|
||||
icon: 'IconSettingsAutomation',
|
||||
isEditable: false,
|
||||
canUpdateAllSettings: false,
|
||||
canAccessAllTools: true,
|
||||
canReadAllObjectRecords: true,
|
||||
canAccessAllTools: false,
|
||||
canReadAllObjectRecords: false,
|
||||
canUpdateAllObjectRecords: true,
|
||||
canSoftDeleteAllObjectRecords: false,
|
||||
canDestroyAllObjectRecords: false,
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import { ApplicationModule } from 'src/engine/core-modules/application/applicati
|
||||
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AiAgentRoleModule } from 'src/engine/metadata-modules/ai-agent-role/ai-agent-role.module';
|
||||
import { AiAgentRoleModule } from 'src/engine/metadata-modules/ai/ai-agent-role/ai-agent-role.module';
|
||||
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module';
|
||||
|
||||
Reference in New Issue
Block a user