## Summary
- Replaces per-provider TypeScript constant files
(`openai-models.const.ts`, `anthropic-models.const.ts`, etc.) with a
single `ai-providers.json` catalog as the source of truth
- Adds runtime model discovery via AI SDK for self-hosted providers,
with `models.dev` enrichment for pricing/capabilities
- Introduces composite model IDs (`provider/modelId`) for canonical,
conflict-free identification
- Simplifies provider configuration: API keys are injected from
environment variables (e.g., `OPENAI_API_KEY`)
- Adds admin panel UI for provider management (add/remove/test), model
discovery, recommended model configuration, and default fast/smart model
selection per workspace
- Removes deprecated config variables (`AI_DISABLED_MODEL_IDS`,
`AUTO_ENABLE_NEW_AI_MODELS`, etc.)
- Adds database migration for composite model ID format
## Test plan
- [ ] Server typecheck passes
- [ ] Frontend typecheck passes
- [ ] Server unit tests pass
- [ ] Frontend unit tests pass
- [ ] CI pipeline green
- [ ] Admin panel AI tab loads correctly
- [ ] Provider discovery works for configured providers
- [ ] Model recommendation toggles persist
- [ ] Default fast/smart model selection works
Made with [Cursor](https://cursor.com)
# What this PR does
Overall naming `universal` versus `flat` is not always the most updated
and so on
Will make a big cleaning tour after I've finished the whole migration
Migrating all `view` and ( filter fields etc ) `field` `object` `index`
to the universal pattern on all `services`, `builder` and `runner`
levels
## Universal and flat optimistic tooling
`addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow`
and its delete counterpart maintain the consistency of
`UniversalFlatEntityMaps` when an entity is created or removed. Beyond
inserting/removing the entity from its own maps, they walk through
`ALL_UNIVERSAL_METADATA_RELATIONS` to update the **aggregator arrays**
on related parent entities — the add appends the new entity's
`universalIdentifier` to the parent's aggregator (e.g. a new viewField's
identifier gets appended to its parent view's
`viewFieldUniversalIdentifiers`), and the delete filters it out. This
keeps the maps in sync so that diff computations and relation lookups
remain accurate throughout the migration building process.
## ALL_UNIVERSAL_METADATA_RELATIONS
`ALL_UNIVERSAL_METADATA_RELATIONS` is the universal counterpart of
`ALL_METADATA_RELATIONS`. It maps each metadata entity to its
many-to-one and one-to-many relations using universal foreign keys
(`*UniversalIdentifier`) instead of database IDs (`*Id`). This allows
migration actions to reference related entities in a workspace-agnostic
way. Relations that are workspace-specific (e.g. `workspace`,
`dataSource`, `userWorkspace`) are set to `null` and skipped during
resolution.
## `workspaceMigrationCreateIdEnrichment`
Reserved to API metadata ( will be able to validate at app installation
lvl )
- Workspace migration `create` actions now carry an optional `id` (and
`fieldIdByUniversalIdentifier` for object/field actions) so that
caller-provided IDs flow through the entire build-validate-run pipeline.
- New `enrichCreateWorkspaceMigrationActionsWithIds` utility resolves
`universalIdentifier → id` mappings after the builder runs and injects
them into the migration actions before the runner persists entities.
- Runner action handlers use the provided IDs instead of generating new
UUIDs, enabling deterministic entity creation for synchronization
workflows.
## `resolveUniversalUpdateRelationIdentifiersToIds`
`resolveUniversalUpdateRelationIdentifiersToIds` converts universal
identifiers (workspace-agnostic, stable keys) in a migration update
payload into concrete database UUIDs, so the update can be applied to a
specific workspace.
It iterates over the many-to-one relations defined in
`ALL_UNIVERSAL_METADATA_RELATIONS` for the given entity type, replaces
each `*UniversalIdentifier` property with its corresponding `*Id` by
looking up the target entity in `allFlatEntityMaps`, and throws if a
non-null identifier can't be resolved.
Used by all `update` action handlers in
`transpileUniversalActionToFlatAction`, avoiding duplicated resolution
logic across handlers.
## What this PR does not
- Migrating twenty-standard declaration to universal
- Migrating all the inputs transpilers to universal
- Migrating all metadata to be fully universal ( we still need to
de-scope the type of all of them and refactor their validator very close
)
---------
Co-authored-by: Charles Bochet <charles@twenty.com>
Upgraded to Storybook 10. We still use `@storybook/test-runner` for
testing since it appears it'd require more work to move from Jest to
Vitest than I initially anticipated, but I completed this PR to fix
`storybook:serve:dev` - it takes time to load, but it works the way it
used to with Storybook 8.
https://github.com/user-attachments/assets/7afc32c6-4bcf-4b37-b83b-8d00d28dda15
# Introduction
In this PR we're:
- Refactoring the workspace migration action type introducing grain over
metadata and operation type ( for example operation `create` and
metadata `field` )
- Thanks to above point we can now factorize the runner optimistic
rendering out of each runner actions-handler file using the existing
into the generic one ( -3200 lines of code here )
- Still thanks to action type refactor we're able to dynamically compose
the response error type only send data when there's here. No more static
counter and static summary error message. This way we won't have to re
run snapshot every time we add a new entity to the engine ( huge
snapshot diff here )
## Noticeable points:
- We introduce an index update action to avoid any complex typing for
not having one or a tuple of actions instead. Now the drop and insert
logic is directly inferred from the update action handler instead of
being two action ( delete index and create index )
## TODO
- [x] Define base actions types
- [x] Migrate all actions to action type and metadata name pattern (
base actions )
- [x] Refactor flat entity validation type to embed metadata name
- [x] Refactor optimistic rendering within runner
- [x] Refactor legacy cache invalidation switch
- [x] Refactor response error format ( dynamic counter again + no empty
entries )
- [x] Try factorizing and removing redundant nor unused type declaration
in metadata actions type intermediary files
- [x] Adapt front to new response error format
## Remarks
- ~~Should create an issue for generic replace flat entity in related
flat entity maps~~ overkill
- Should create an issue for oneToMany foreignKey being nullable not
always cascade delete optimistic rendering edge case to either docs or
fix it in delete flat entity and related entity ( re-code the pg
cascading behavior )
- We could also factorize the builder to only implement validators and
not the intermediary file
## Summary
This PR introduces a Skills system for AI agents, inspired by the [Agent
Skills specification](https://agentskills.io/specification).
## Changes
### Backend
- **SkillEntity**: New database entity with migration for storing skills
- **V2 Sync Mechanism**: Implemented FlatSkill, builders, validators,
and action handlers following the v2 flat entity pattern
- **Standard Skills**: Pre-defined skills (workflow-building,
data-manipulation, dashboard-building, metadata-building, research,
code-interpreter, xlsx, pdf, docx, pptx)
- **GraphQL API**: CRUD operations for skills with proper guards and
permissions
- **Workspace Cache**: Integrated skills into the workspace cache system
### Frontend
- **Skills Table**: Searchable table in AI settings showing all skills
- **Skill Form**: Create/edit page with Label (primary), Description,
and Content (markdown editor)
- **API Name**: Following existing patterns, name is derived from label
with advanced settings toggle for custom API names
- **Standard vs Custom**: Standard skills are read-only, custom skills
can be edited/deleted
## Key Design Decisions
- Skills are stored in the database (Salesforce-like approach) rather
than files
- Name is derived from Label by default (isLabelSyncedWithName pattern)
- Skills reference functions/files via @ mentions in markdown content
rather than explicit relations
- Standard skills are synced from code, custom skills are created via UI
## Screenshots
Skills table and form UI follow existing settings patterns.
## Testing
- [x] Lint passes
- [x] Typecheck passes
- [ ] CI tests
## Introduction
On the side hanlded PR with a // agents on another repo
Made several iterations to fix behavior and direction
Find below auto-generated PR description
closes https://github.com/twentyhq/core-team-issues/issues/2037
Created generic tooling for entity circular dep checking, will be useful
for permissions validation too @Weiko
## Migrate `viewFilterGroup` entity to v2 flat architecture
### Summary
Migrates the `viewFilterGroup` entity from v1 to the v2 flat entity
architecture, following the established patterns for other v2 entities
like `viewFilter`, `view`, and `viewField`.
### Changes
**Types & Constants**
- Added `FlatViewFilterGroup` and `FlatViewFilterGroupMaps` types
- Added editable properties constant for `viewFilterGroup`
- Registered `viewFilterGroup` in `ALL_METADATA_NAME`,
`ALL_METADATA_RELATION_PROPERTIES`,
`ALL_METADATA_MANY_TO_ONE_RELATIONS`, and related constants
**Cache Service**
- Created `WorkspaceFlatViewFilterGroupMapCacheService` with proper
relation loading for `viewFilters` and `childViewFilterGroups`
- Updated `WorkspaceFlatViewMapCacheService` to load `viewFilterGroups`
relation
**Builder & Validator**
- Created `WorkspaceMigrationV2ViewFilterGroupActionsBuilderService`
- Created `FlatViewFilterGroupValidatorService` with creation, update,
and deletion validation
- Integrated validation into the orchestrator service (runs before
`viewFilter` validation)
**Action Handlers**
- Created create, update, and delete action handlers for
`viewFilterGroup`
**Service Migration**
- Rewrote `ViewFilterGroupService` to use v2 migration pattern with
`WorkspaceMigrationValidateBuildAndRunService`
- Created utility functions for transforming DTOs to flat entities
**Database Migration**
- Added migration to make `parentViewFilterGroupId` foreign key
deferrable (handles self-referential parent/child insertions)
**ViewFilter Integration**
- Added `viewFilterGroupId` validation in
`FlatViewFilterValidatorService`
- Updated `viewFilter` many-to-one relations to include
`viewFilterGroup`
**Tests**
- Added integration tests for successful creation, update, deletion, and
destruction
- Added failing test cases for non-existent entities and invalid
references
- Added failing test for `viewFilter` creation with non-existent
`viewFilterGroupId`
### Breaking Changes
None - existing API contracts are preserved.
## Context
This PR adds the core structure for RLS implementation:
- RLS data model
- RLS service layer
- RLS WorkspaceMigration and Syncable Entity + cache + Validations
- RLS resolver layer
- ORM layer with RLS Predicate to ORM WHERE clause conversion with
workspaceMember record transposition
Tests are missing though
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Establishes core row-level permissions infrastructure and enforcement
across the stack.
>
> - Backend: new `rowLevelPermissionPredicate` and
`rowLevelPermissionPredicateGroup` entities, TypeORM migration, feature
flag `IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED`, flat-entity
maps/cache wiring, services and GraphQL resolvers for CRUD, and
inclusion of `workspaceMember` in auth context
> - ORM: applies row-level permission predicates to SELECT, DELETE, and
SOFT DELETE query builders; propagates context through
GlobalWorkspaceOrmManager/EntityManager
> - GraphQL: generated schema/types/queries/mutations for
creating/updating/deleting/fetching predicates and groups
> - Frontend: settings page adds a gated "Record-level" section
(placeholder) and metadata error handler labels for new entities
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
fe955cc4588a92157afa6795fb574189a4be1e93. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
## Summary
This PR enforces that all custom exceptions must provide a
`userFriendlyMessage`, ensuring end users always see readable error
messages.
## Changes
### Core Changes
- **`CustomException` simplified**: Removed the `ForceFriendlyMessage`
generic parameter - `userFriendlyMessage` is now always required
- **Type safety**: The constructor now requires `{ userFriendlyMessage:
MessageDescriptor }` (no longer optional)
### Updated Files
- **74+ exception classes** updated to provide default user-friendly
messages using Lingui `msg` macro
- Each exception class has a sensible fallback message (e.g., `msg\`An
authentication error occurred.\``)
- Exception classes that had code-specific message maps retain their
behavior
## Benefits
- **Compile-time enforcement**: Forgetting to add a user-friendly
message now causes a TypeScript error
- **Better UX**: End users always see a localized, human-readable error
message
- **Simpler API**: No more boolean generic parameter to think about
## Testing
- `npx nx run twenty-server:typecheck` passes
- `npx nx run twenty-server:lint` passes
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Enforces `userFriendlyMessage` on `CustomException` and updates all
exception classes to supply localized default messages, with
filters/tests adjusted accordingly.
>
> - **Core**:
> - Enforce required `userFriendlyMessage` in `CustomException` (remove
optional generic; constructor now requires `{ userFriendlyMessage:
MessageDescriptor }`).
> - **Exceptions**:
> - Update ~70+ exception classes to set default localized messages via
Lingui `msg` maps and pass them in constructors (e.g., `AuthException`,
`ObjectMetadataException`, `FieldMetadataException`, etc.).
> - Add fallback messages where needed (e.g., `INTERNAL_SERVER_ERROR` or
domain-specific defaults).
> - **HTTP/GraphQL Filters**:
> - Ensure fallbacks create `UnknownException` with `msg` for
user-friendly text in REST/GraphQL exception filters.
> - **Tests**:
> - Adjust unit tests to pass `userFriendlyMessage` to exceptions.
> - Update Jest snapshots to include `extensions.userFriendlyMessage` or
message objects where applicable.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
221004fdfc0d97b7d152a258b347bf571e70f10e. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
# Introduction
In this pullrequest have been migrated to the flat standard entities:
Role, Agent and RoleTargets.
## What happens
- Removed createStandardMorph tool util in favor of dynamic typing of
`createMorphOrRelationStandardField`
- Implemented a command to remove standard agents and their role that
has been removed in https://github.com/twentyhq/twenty/pull/16513 also
added a default role target to data manipulator role to the only
remaining agent
- Implemented an agent deleteMany service handler
## Summary
- Replace the agent search mechanism with a new skills-based system
- Add a `skills` module with predefined skill definitions that the AI
can load on demand
- Remove specialized agents (workflow-builder, data-manipulator,
dashboard-builder, metadata-builder, researcher), keeping only the
helper agent
- Add `recordReferences` to workflow creation tool for chip linking in
the UI
## Changes
### New Skills Module
- `skill-definitions.ts` - Contains 5 skill definitions with detailed
instructions
- `skills.service.ts` - Service to get skills by name
- `load-skill.tool.ts` - Tool for AI to load skills explicitly
### Removed
- `agent-search.tool.ts` - Replaced by skill loading
- Specialized agent definitions (converted to skills)
### Updated
- Chat execution now shows skill catalog in system prompt
- Workflow creation returns `recordReferences` for UI linking
## Test plan
- [ ] Verify AI can load skills using `load_skill` tool
- [ ] Verify skill content is returned correctly
- [ ] Verify workflow creation shows clickable chip in chat
- [ ] Verify helper agent still works
## Summary
This PR significantly simplifies the AI chat architecture by removing
complex routing/planning mechanisms and introduces clickable record
links in AI responses.
## Changes
### AI Chat Architecture Simplification
- **Removed** the entire `ai-chat-router` module (~850 lines) including:
- Strategy decider service
- Plan generator service
- Complex routing logic
- **Removed** agent execution planning services (~700 lines):
- `agent-execution.service.ts`
- `agent-plan-executor.service.ts`
- `agent-tool-generator.service.ts`
- **Added** centralized `ToolRegistryService` for tool management:
- Builds searchable tool index (database, action, workflow tools)
- Provides tool lookup by name
- Supports agent search for loading expertise
- **Added** `ChatExecutionService` as simple replacement:
- Includes full tool catalog in system prompt
- Pre-loads common tools (find/create/update for company, person,
opportunity, task, note)
- Uses `load_tools` mechanism for dynamic tool activation
- Enables native web search by default
### Record References in AI Responses
- Added `recordReferences` field to tool outputs for create, find, and
update operations
- Implemented `[[record:objectName:recordId:displayName]]` syntax for AI
to reference records
- Created `RecordLink` component that renders clickable chips with
object icons
- Integrated record link parsing into the markdown renderer
- Users can now click directly on created/found records in AI responses
### Workflow Agent Fixes
- Fixed cache invalidation issue when creating agents in workflows
- Added default prompt for workflow-created agents to prevent validation
errors
- Relaxed agent validation to only check properties being updated (not
all required properties)
### Code Quality Improvements
- Extracted `getRecordDisplayName` utility that mirrors frontend's
`getLabelIdentifierFieldValue` logic
- Uses object metadata to determine the correct label identifier field
- Handles `FULL_NAME` composite type for person/workspaceMember objects
- Shared across create, find, and update record services
## Net Impact
- **~1,200 lines deleted** (complex routing/planning code)
- **~500 lines added** (simpler tool registry + record links)
- Significantly reduced code complexity
- Better tool discovery through full catalog in system prompt
- Improved UX with clickable record references
## Testing
- Typecheck passes
- Lint passes
- Manual testing of AI chat with record creation and linking
## Summary
Consolidates the AI tool provider architecture by creating a single
`ToolProviderService` as the entry point for all tool generation. This
removes multiple intermediate services and simplifies the codebase.
## Changes
### New Architecture
- **`ToolProviderService`**: Single service for all tool generation
with:
- `getTools(spec)` - Get tools by category with permissions
- `getToolByType(type)` - Get specific tool for workflow execution
- **`ToolCategory` enum**: Declarative specification of tool types:
- `DATABASE_CRUD` - Record CRUD operations
- `ACTION` - HTTP requests, email sending, article search
- `WORKFLOW` - Workflow management tools
- `METADATA` - Object/field metadata tools
- `NATIVE_MODEL` - Model-specific tools (e.g., web search)
- **`ToolSpecification` type**: Clean API for requesting tools with
permissions
### Removed
- `AiToolsModule` - No longer needed
- `ToolService` - Logic inlined into ToolProviderService
- `ToolAdapterService` - Logic inlined into ToolProviderService
- `ToolRegistryService` - Logic inlined into ToolProviderService
### Updated
- All consumers (agents, chat, MCP, workflows) now use
`ToolProviderService`
- Test files updated accordingly
## Stats
- **547 insertions, 1146 deletions** (net ~600 lines removed)
- 4 services deleted
- 1 module deleted
## Testing
- [x] Typecheck passes
- [x] Lint passes
# Introduction
Migrating `pageLayoutTab` to the v2 engine
- Types and constants
- Builder and validate
- Runner
Introduced a new `StrictSyncableEntity` that enforces that
`universalIdentifier` and `applicationId` are defined
As these entities are brand new we could enforce this rule already
This still requires a migration command to associate the existing
entities to custom workspace application instance and define
universalIdentifier
Handled retro-comp of the migration through a migration as upgrade
command fallback
---------
Co-authored-by: bosiraphael <raphael.bosi@gmail.com>
# Introduction
Closes https://github.com/twentyhq/core-team-issues/issues/1980
In this PR we migrate the agent from v1 to v2.
## New FlatRoleTargetByAgentIdMaps
Derivated the `flatRoleTargetMaps` to be building a
`flatRoleTargetByAgentIdMaps` to ease retrieving a roleId to associate
to an agent
## Coverage
Added strong coverage on both failing and successful CRU agents
operations
---------
Co-authored-by: Weiko <corentin@twenty.com>
## Context
We've recently introduced a new workspace cache service which now acts
as a cache access and local storage for all workspace related data,
deprecating the individual specific services.
- Better performance through multiple caching/fetching strategies
- Consistent data access patterns across the codebase
- Reduced redis queries through MGET/MSET/PIPELINE with multiple cache
keys
## Context
Deprecating the old objectMetadataMap type in favour of split flat
entities to match with our new caching.
In the long run, trying to achieve:
- Better performance through caching
- Consistent data access patterns across the codebase
- Reduced database queries
Now that everything is based on flat entities, which are cached, we can
finish the refactoring of workspace context cache which should already
improve performances.
Then the last step will be to consume that new cache in the new global
datasource to get rid of the many workspace datasources stored in the
server
## 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 -->
## Overview
This PR replaces the dynamic agent handoff system with a more
predictable planning-based router that decides upfront how to handle
multi-agent coordination.
## Major Changes
### 🔄 Architecture Shift: Handoffs → Planning
**Removed:**
- `AgentHandoffEntity` and handoff tracking system
- `AgentHandoffService` and `AgentHandoffExecutorService`
- Dynamic agent-to-agent transfers during execution
- Handoff tool generation and description templates
**Added:**
- `AiRouterService` with two strategies: `simple` (single agent) and
`planned` (multi-agent)
- `AgentPlanExecutorService` for executing multi-step plans
- Plan validation (cycle detection, dependency resolution)
- `UnifiedRouterResult` type with discriminated union
### 🤖 New Standard Agents
Added two new specialized agents:
- **Researcher Agent**: Web search, fact-finding, competitive
intelligence
- **Code Agent**: TypeScript function generation for serverless
workflows
### 🏗️ Router Refactoring (Latest)
Split router responsibilities into focused services:
- `AiRouterStrategyDeciderService`: Decides simple vs planned strategy
- `AiRouterPlanGeneratorService`: Generates and validates execution
plans
- `AiRouterService`: Coordinates between services (reduced from 426→275
lines)
### ⚙️ Configuration Improvements
- Added `outputStrategy` to agent definitions (`direct` vs `synthesize`)
- Removed hardcoded special cases for workflow-builder
- Added `plannerModel` field to workspace entity
- Increased `MAX_STEPS` from 10 to 25 for complex workflows
### 📝 Agent Prompt Refinements
Significantly simplified prompts for better clarity:
- Workflow Builder: 51→36 lines
- Helper: 49→28 lines
- Data Manipulator: Enhanced with sorting guidance
### 🔍 Enhanced Debugging
- Plan reasoning and step count in data message parts
- Router debug info with token usage tracking
- Better logging throughout execution pipeline
## Benefits
1. **Simpler Mental Model**: Router decides upfront vs dynamic transfers
2. **Better Predictability**: Users see the plan before execution
3. **Cleaner Architecture**: SRP with focused services
4. **Configuration Over Code**: Agent behavior via config, not hardcoded
logic
5. **Plan Validation**: Catches invalid dependencies and cycles
## Migration Notes
- Database migration removes `agentHandoff` table
- Adds `plannerModel` column to workspace table
- No API breaking changes (agent endpoints unchanged)
## Testing
- Integration tests updated to remove handoff dependencies
- Agent tool test utilities simplified
- Plan validation covered by new logic
## Next Steps (Future PRs)
- Parallel execution of independent plan steps
- Dynamic re-planning based on results
- Plan caching for common routing patterns
- Error recovery strategies in plan executor
## Context
Deprecating legacy ObjectMetadata from cache in favor of flat entities.
Introducing utils to build byName/byNameSingular/byNamePlural in
isolated cases
## Next
- I had to introduce a util to build from flat to legacy
objectMetadataMaps, we should instead use flat maps directly when needed
(datasource, schema generation, etc)
- Deprecate metadata version in the cache
- Use the new cache strategy for flat entities with permissions and
feature flags and inject in the global datasource context
## Summary
This PR adds configurable response format support for AI agents,
allowing them to return either plain text or structured JSON data based
on a defined schema.
## Key Features
### 1. Agent Response Format Configuration
- Added `AgentResponseFormat` type supporting:
- `text`: Returns plain text responses (default)
- `json`: Returns structured JSON based on defined schema
- New `AgentResponseSchema` type moved to `twenty-shared/ai` for sharing
between frontend/backend
### 2. Settings UI
- New `SettingsAgentResponseFormat` component for configuring response
format
- Visual schema builder for defining JSON output structure
- Real-time validation and preview
- Integrated into agent settings tab
### 3. Workflow Integration
- AI Agent workflow action automatically uses agent's configured
response format
- Output schema dynamically generated from agent's response format
- Workflow variable picker shows structured fields for JSON responses
- Backward compatible with existing text-only agents
### 4. Backend Implementation
- Added `convertAgentSchemaToZod` utility to validate JSON responses
- Agent executor service handles both text and JSON generation
- Automatic agent creation/cloning when adding AI agent steps to
workflows
- Unique agent naming with conflict resolution
### 5. Database Migration
- Migration `1763622159656-update-agent-response-format.ts`
- Sets default `responseFormat` to `{"type":"text"}` for existing agents
- Updated all standard agents with proper response format
## Changes by Module
### Frontend (`twenty-front`)
- 🆕 `AgentResponseFormat` type
- 🆕 `SettingsAgentResponseFormat` component
- ✏️ Updated `WorkflowEditActionAiAgent` to support response format
configuration
- 🗑️ Removed deprecated `useAiAgentOutputSchema` hook and
`AiAgentOutputSchema` type
### Backend (`twenty-server`)
- 🆕 `AgentResponseFormat` type in agent entity
- 🆕 `convertAgentSchemaToZod` utility for schema validation
- ✏️ Updated `AiAgentExecutorService` to handle both text and JSON
generation
- ✏️ Updated `WorkflowSchemaWorkspaceService` to generate output schema
from agent config
- ✏️ Enhanced `WorkflowVersionStepOperationsWorkspaceService` with agent
creation/cloning
- 🆕 Agent naming constants for conflict resolution
### Shared (`twenty-shared`)
- 🆕 `AgentResponseSchema` type
- 🆕 `ModelConfiguration` type moved to shared package
- Updated exports in `ai/index.ts`
## Code Quality
- Removed useless comments following code style guidelines
- All linter checks passed
- Type-safe implementation with proper TypeScript types
## Testing
- ✅ Database migration tested
- ✅ Agent creation/cloning in workflows verified
- ✅ Response format switching (text ↔ JSON) validated
- ✅ Backward compatibility with existing agents confirmed
## Migration Notes
- Existing agents will have `responseFormat: {type: 'text'}` set
automatically
- No breaking changes - all existing functionality preserved
- Agents can be updated to use JSON format through settings UI
# Introduction
Remove the v2 feature flag for view-field field-metadata and
object-metadata metadata entities
## Some details
- Disabled nestjs-query for object metadata creation and explicitly
calling it
- removed all v1 integration tests files
## Remarks
Not remove v2 referencing in both filenaming right now will handle that
globally later
## Breaking change
Due to object metadata resolver createOne standardization had to rename
the input from `CreateObjectInput` to `CreateOneObjectInput`
Adds intelligent routing system that automatically selects the best
agent for user queries based on conversation context.
### Changes:
- Added `routerModel` column to workspace table for configurable router
LLM selection
- Implemented `RouterService` with conversation history analysis and
agent matching logic
- Created router settings UI in AI Settings page with model dropdown
- Removed agent-specific thread associations - threads are now
agent-agnostic
- Added real-time routing status notification in chat UI with shimmer
effect
- Removed automatic default assistant agent creation
- Renamed GraphQL operations from agent-specific to generic (e.g.,
`agentChatThreads` → `chatThreads`)
---------
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
Implements permission intersection (AND logic) to prevent permission
escalation when agents act on behalf of users.
### Changes:
- **Permission Intersection**: Operations requiring both user AND agent
permissions
- **RoleContext Type**: Unified type supporting single `roleId` or
multiple `roleIds` for intersection
- **CRUD Services**: Updated to accept `roleContext` for granular
permission control
- **Agent Integration**: Chat agents now use user + agent role
intersection for all operations
- **ORM Layer**: Enhanced `getRepository` to support multi-role
permission checks
### Related:
- Part 2 of ["Acting on behalf of user" concept
PR](https://github.com/twentyhq/twenty/pull/15103)
[Closes#1661](https://github.com/twentyhq/core-team-issues/issues/1661)
---------
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
## Context
- All flatEntity should extend SyncableEntity
- SyncableEntity should now have applicationId and application relation
- Fix syncApp deletion, should now properly use migration v2 to delete
syncable entities
We want to update UserWorkspacePermissions from
```
export type UserWorkspacePermissions = {
permissionFlags: Record<PermissionFlagType, boolean>;
objectRecordsPermissions: Record<PermissionsOnAllObjectRecords, boolean>;
objectPermissions: ObjectsPermissionsDeprecated;
};
```
to
```
export type UserWorkspacePermissions = {
permissionFlags: Record<PermissionFlagType, boolean>;
objectsPermissions: ObjectsPermissions;
};
```
`ObjectsPermissionsDeprecated` and `ObjectsPermissions` are actually
very similar, they only have different key names (`canRead` vs
`canReadObjectRecords`)
To avoid brutal breaking changes, we will proceed in multiple steps:
1. This PR: adapt FE so it does not call objectRecordsPermissions
anymore + add the new objectsPermissions to UserWorkspacePermissions
without calling it yet in the FE
2. Remove objectRecordsPermissions in BE + use objectsPermissions in FE
instead of objectPermissions
3. Remove objectPermissions
- Renamed `WorkflowActionAdapter` to `ToolExecutorWorkflowAction`
- Renamed `settingPermission` table to `permissionFlag` and `setting`
column to `flag`
- Decoupled the send email logic from workflows to tools
- Add new `Tools Permission` section in FE
---------
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
# Introduction
Following `FieldMetadataInterface` deprecation in
https://github.com/twentyhq/twenty/pull/13264
As for the previous PR will rename and remove all the file in a
secondary PR to avoid conflicts and over loading this one
## Improvements
Removed optional properties from the `objectMetadataEntity` model and
added utils to retrieve test data
## Notes
By touching to `ObjectMetadataDTO` I would have expected a twenty-front
codegenerated types mutation, but it does not seem to be granular enough
to null/undefined coercion
- Added a generic HTTP request tool, allowing agents and workflows to
make HTTP requests to external APIs with configurable method, headers,
and body.
- Decoupled HTTP request workflow nodes from workflow-specific types and
factories, introducing a generic tool interface.
- Updated agent system prompts to include explicit guidance for the HTTP
request tool, including when and how to use it, and how to communicate
limitations.
### Demo
https://github.com/user-attachments/assets/129bc445-a277-4a19-95ab-09f890f8f051