Skip to content
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
7fff6db
feat: add icon to personal and workflow agent
autologie Dec 10, 2025
5187b59
revert workflow agent grouping for now
autologie Dec 10, 2025
ba8bbba
change icon for personal agents
autologie Dec 10, 2025
c90295b
adjust icon size
autologie Dec 10, 2025
645a43f
fix: use agent icon in model selector
autologie Dec 10, 2025
dbb905e
format
autologie Dec 10, 2025
f4c1cd6
design feedback
autologie Dec 11, 2025
3b41d2d
add skeleton
autologie Dec 11, 2025
844e627
refactor
autologie Dec 11, 2025
3e47533
fix: cache icon
autologie Dec 11, 2025
b0a1411
fix: make icon nullable
autologie Dec 11, 2025
6dc84bd
remove projectName for now
autologie Dec 11, 2025
86372ae
fix import order
autologie Dec 11, 2025
cfe2dc9
revert some changes
autologie Dec 11, 2025
84a1650
fix test
autologie Dec 11, 2025
752a1fa
refactor
autologie Dec 11, 2025
a4d7d1b
revert some changes
autologie Dec 11, 2025
bff4a3e
add tests
autologie Dec 11, 2025
5f321be
AI review
autologie Dec 11, 2025
a061d6b
refactor: remove agentIcon column from session table
autologie Dec 12, 2025
198defb
Merge branch 'master' into chat-split-custom-agents
autologie Dec 12, 2025
50614ef
fix: show icon even if agent is no longer available
autologie Dec 12, 2025
6fdb3b0
change agentId type to UUID and add FK constraint
autologie Dec 12, 2025
b6b09a1
Merge branch 'master' into chat-split-custom-agents
autologie Dec 12, 2025
c888ab8
fix error in conflict resolution
autologie Dec 12, 2025
8327d14
Merge branch 'master' into chat-split-custom-agents
Cadiac Dec 14, 2025
9e4a2c0
add FK constraint on agentId column in chat messages table
autologie Dec 15, 2025
181907c
add explicit name to FKs
autologie Dec 15, 2025
1840e1d
update migration timestamp
autologie Dec 15, 2025
7449aff
feat: add tooltip in model selector
autologie Dec 15, 2025
ab79ad0
exclude FKs from migration
autologie Dec 15, 2025
bd4daeb
refactor
autologie Dec 15, 2025
f40df38
Merge branch 'master' into chat-split-custom-agents
autologie Dec 15, 2025
41cced4
Merge branch 'master' into chat-split-custom-agents
Cadiac Dec 15, 2025
c6e0246
fix: add back migration for updating column type
autologie Dec 15, 2025
752c6f2
Merge branch 'master' into chat-split-custom-agents
autologie Dec 15, 2025
328d3c1
lint
autologie Dec 15, 2025
2f6ce74
fix type
autologie Dec 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions packages/@n8n/api-types/src/chat-hub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,21 @@ export const chatHubLLMProviderSchema = z.enum([
]);
export type ChatHubLLMProvider = z.infer<typeof chatHubLLMProviderSchema>;

/**
* Schema for icon or emoji representation
*/
export const agentIconOrEmojiSchema = z.discriminatedUnion('type', [
z.object({
type: z.literal('icon'),
value: z.string(),
}),
z.object({
type: z.literal('emoji'),
value: z.string(),
}),
]);
export type AgentIconOrEmoji = z.infer<typeof agentIconOrEmojiSchema>;

export const chatHubProviderSchema = z.enum([
...chatHubLLMProviderSchema.options,
'n8n',
Expand Down Expand Up @@ -222,6 +237,7 @@ export interface ChatModelDto {
model: ChatHubConversationModel;
name: string;
description: string | null;
icon: AgentIconOrEmoji | null;
updatedAt: string | null;
createdAt: string | null;
metadata: ChatModelMetadataDto;
Expand Down Expand Up @@ -363,6 +379,7 @@ export interface ChatHubSessionDto {
workflowId: string | null;
agentId: string | null;
agentName: string;
agentIcon: AgentIconOrEmoji | null;
createdAt: string;
updatedAt: string;
tools: INode[];
Expand Down Expand Up @@ -414,6 +431,7 @@ export interface ChatHubAgentDto {
id: string;
name: string;
description: string | null;
icon: AgentIconOrEmoji | null;
systemPrompt: string;
ownerId: string;
credentialId: string | null;
Expand All @@ -427,6 +445,7 @@ export interface ChatHubAgentDto {
export class ChatHubCreateAgentRequest extends Z.class({
name: z.string().min(1).max(128),
description: z.string().max(512).optional(),
icon: agentIconOrEmojiSchema,
systemPrompt: z.string().min(1),
credentialId: z.string(),
provider: chatHubLLMProviderSchema,
Expand All @@ -437,6 +456,7 @@ export class ChatHubCreateAgentRequest extends Z.class({
export class ChatHubUpdateAgentRequest extends Z.class({
name: z.string().min(1).max(128).optional(),
description: z.string().max(512).optional(),
icon: agentIconOrEmojiSchema.optional(),
systemPrompt: z.string().min(1).optional(),
credentialId: z.string().optional(),
provider: chatHubProviderSchema.optional(),
Expand Down
2 changes: 2 additions & 0 deletions packages/@n8n/api-types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ export {
type ChatHubAgentDto,
ChatHubCreateAgentRequest,
ChatHubUpdateAgentRequest,
type AgentIconOrEmoji,
agentIconOrEmojiSchema,
type EnrichedStructuredChunk,
type ChatHubAgentTool,
UpdateChatSettingsRequest,
Expand Down
1 change: 1 addition & 0 deletions packages/@n8n/backend-test-utils/src/test-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ type EntityName =
| 'DataTableColumn'
| 'ChatHubSession'
| 'ChatHubMessage'
| 'ChatHubAgent'
| 'OAuthClient'
| 'AuthorizationCode'
| 'AccessToken'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { MigrationContext, ReversibleMigration } from '../migration-types';

const table = 'chat_hub_agents';

export class AddIconToAgentTable1765788427674 implements ReversibleMigration {
async up({ schemaBuilder: { addColumns, column } }: MigrationContext) {
// Add icon column to agents table (nullable)
await addColumns(table, [column('icon').json]);
}

async down({ schemaBuilder: { dropColumns } }: MigrationContext) {
// Drop icon column
await dropColumns(table, ['icon']);
}
}
2 changes: 2 additions & 0 deletions packages/@n8n/db/src/migrations/mysqldb/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ import { CreateDynamicCredentialResolverTable1764682447000 } from '../common/176
import { AddDynamicCredentialEntryTable1764689388394 } from '../common/1764689388394-AddDynamicCredentialEntryTable';
import { BackfillMissingWorkflowHistoryRecords1765448186933 } from '../common/1765448186933-BackfillMissingWorkflowHistoryRecords';
import { AddResolvableFieldsToCredentials1765459448000 } from '../common/1765459448000-AddResolvableFieldsToCredentials';
import { AddIconToAgentTable1765788427674 } from '../common/1765788427674-AddIconToAgentTable';
import type { Migration } from '../migration-types';

export const mysqlMigrations: Migration[] = [
Expand Down Expand Up @@ -255,4 +256,5 @@ export const mysqlMigrations: Migration[] = [
AddDynamicCredentialEntryTable1764689388394,
BackfillMissingWorkflowHistoryRecords1765448186933,
AddResolvableFieldsToCredentials1765459448000,
AddIconToAgentTable1765788427674,
];
2 changes: 2 additions & 0 deletions packages/@n8n/db/src/migrations/postgresdb/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ import { CreateDynamicCredentialResolverTable1764682447000 } from '../common/176
import { AddDynamicCredentialEntryTable1764689388394 } from '../common/1764689388394-AddDynamicCredentialEntryTable';
import { BackfillMissingWorkflowHistoryRecords1765448186933 } from '../common/1765448186933-BackfillMissingWorkflowHistoryRecords';
import { AddResolvableFieldsToCredentials1765459448000 } from '../common/1765459448000-AddResolvableFieldsToCredentials';
import { AddIconToAgentTable1765788427674 } from '../common/1765788427674-AddIconToAgentTable';
import type { Migration } from '../migration-types';

export const postgresMigrations: Migration[] = [
Expand Down Expand Up @@ -255,4 +256,5 @@ export const postgresMigrations: Migration[] = [
AddDynamicCredentialEntryTable1764689388394,
BackfillMissingWorkflowHistoryRecords1765448186933,
AddResolvableFieldsToCredentials1765459448000,
AddIconToAgentTable1765788427674,
];
2 changes: 2 additions & 0 deletions packages/@n8n/db/src/migrations/sqlite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ import { CreateWorkflowPublishHistoryTable1764167920585 } from '../common/176416
import { CreateDynamicCredentialResolverTable1764682447000 } from '../common/1764682447000-CreateCredentialResolverTable';
import { AddDynamicCredentialEntryTable1764689388394 } from '../common/1764689388394-AddDynamicCredentialEntryTable';
import { BackfillMissingWorkflowHistoryRecords1765448186933 } from '../common/1765448186933-BackfillMissingWorkflowHistoryRecords';
import { AddIconToAgentTable1765788427674 } from '../common/1765788427674-AddIconToAgentTable';
import type { Migration } from '../migration-types';

const sqliteMigrations: Migration[] = [
Expand Down Expand Up @@ -247,6 +248,7 @@ const sqliteMigrations: Migration[] = [
AddDynamicCredentialEntryTable1764689388394,
BackfillMissingWorkflowHistoryRecords1765448186933,
AddResolvableFieldsToCredentials1764689448000,
AddIconToAgentTable1765788427674,
];

export { sqliteMigrations };
14 changes: 12 additions & 2 deletions packages/@n8n/utils/src/string/truncate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ export const truncate = (text: string, length = 30): string =>
* - Remove chars just before the last word, as long as the last word is under 15 chars
* - Otherwise preserve the last 5 chars of the name and remove chars before that
*/
export function truncateBeforeLast(text: string, maxLength: number): string {
export function truncateBeforeLast(
text: string,
maxLength: number,
lastCharsLength: number = 5,
): string {
const chars: string[] = [];

const segmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' });
Expand Down Expand Up @@ -38,7 +42,13 @@ export function truncateBeforeLast(text: string, maxLength: number): string {
}
}

if (lastCharsLength < 1) {
return chars.slice(0, maxLength).join('') + ellipsis;
}

return (
chars.slice(0, maxLength - 5 - ellipsisLength).join('') + ellipsis + chars.slice(-5).join('')
chars.slice(0, maxLength - lastCharsLength - ellipsisLength).join('') +
ellipsis +
chars.slice(-lastCharsLength).join('')
);
}
Loading
Loading