mirror of
https://github.com/n8n-io/n8n.git
synced 2026-06-04 18:49:20 +02:00
feat(core): Add sub-agent session linkage migration (#31534)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
4e0e0ed11a
commit
25f2d3cf32
|
|
@ -0,0 +1,86 @@
|
|||
import type { IrreversibleMigration, MigrationContext } from '../migration-types';
|
||||
|
||||
/**
|
||||
* Adds the sub-agent session-linkage columns to `agent_execution_threads`
|
||||
* (parentThreadId / parentAgentId) and widens the agent thread-id columns to
|
||||
* varchar(128).
|
||||
*
|
||||
* Agent thread ids are not bare uuids — several surfaces scope them with a
|
||||
* prefix and a user id (e.g. the test chat's `test-<agentId>:<userId>`, the
|
||||
* builder's `builder:<agentId>`). Those values exceed the original varchar(36)
|
||||
* of the SDK memory thread (`agents_threads.id`) and the session records
|
||||
* (`agent_execution_threads.id`, `agent_execution.threadId`), so widen those id
|
||||
* columns to varchar(128). `parentThreadId` holds such a parent thread id, so it
|
||||
* is created at varchar(128) directly. Known generated formats stay well below
|
||||
* 128 chars (for example, `test-<agentId>:<userId>` is about 78 chars with UUIDs).
|
||||
*/
|
||||
const COLUMNS_TO_WIDEN: Array<{ table: string; column: string }> = [
|
||||
{ table: 'agents_threads', column: 'id' },
|
||||
{ table: 'agent_execution_threads', column: 'id' },
|
||||
{ table: 'agent_execution', column: 'threadId' },
|
||||
];
|
||||
|
||||
const SQLITE_DECLARED_TYPE_REPLACEMENTS: Array<{ table: string; from: string; to: string }> = [
|
||||
{ table: 'agents_threads', from: '"id" varchar(36)', to: '"id" varchar(128)' },
|
||||
{
|
||||
table: 'agent_execution_threads',
|
||||
from: '"id" varchar(36)',
|
||||
to: '"id" varchar(128)',
|
||||
},
|
||||
{
|
||||
table: 'agent_execution',
|
||||
from: '"threadId" varchar(36)',
|
||||
to: '"threadId" varchar(128)',
|
||||
},
|
||||
];
|
||||
|
||||
export class AddSubAgentLinkageToAgentExecutionThreads1784000000022
|
||||
implements IrreversibleMigration
|
||||
{
|
||||
async up({
|
||||
schemaBuilder: { addColumns, column },
|
||||
isPostgres,
|
||||
isSqlite,
|
||||
runQuery,
|
||||
escape,
|
||||
tablePrefix,
|
||||
}: MigrationContext) {
|
||||
await addColumns('agent_execution_threads', [
|
||||
column('parentThreadId')
|
||||
.varchar(128)
|
||||
.comment('Parent session thread id that delegated this subagent run.'),
|
||||
column('parentAgentId')
|
||||
.varchar(36)
|
||||
.comment('Saved agent id of the parent that delegated this subagent run.'),
|
||||
]);
|
||||
|
||||
if (isPostgres) {
|
||||
for (const { table, column: columnName } of COLUMNS_TO_WIDEN) {
|
||||
await runQuery(
|
||||
`ALTER TABLE ${escape.tableName(table)} ALTER COLUMN ${escape.columnName(columnName)} TYPE VARCHAR(128);`,
|
||||
);
|
||||
}
|
||||
} else if (isSqlite) {
|
||||
// SQLite does not enforce varchar limits, but keep the declared schema in sync for documentation.
|
||||
await this.widenSqliteDeclaredColumnTypes({ runQuery, tablePrefix });
|
||||
}
|
||||
}
|
||||
|
||||
private async widenSqliteDeclaredColumnTypes({
|
||||
runQuery,
|
||||
tablePrefix,
|
||||
}: Pick<MigrationContext, 'runQuery' | 'tablePrefix'>) {
|
||||
await runQuery('PRAGMA writable_schema = 1;');
|
||||
|
||||
try {
|
||||
for (const { table, from, to } of SQLITE_DECLARED_TYPE_REPLACEMENTS) {
|
||||
await runQuery(
|
||||
"UPDATE sqlite_master SET sql = replace(sql, :from, :to) WHERE type = 'table' AND name = :tableName",
|
||||
{ from, to, tableName: `${tablePrefix}${table}` },
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
await runQuery('PRAGMA writable_schema = 0;');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -197,6 +197,7 @@ import { CreateAgentFilesTable1784000000018 } from '../common/1784000000018-Crea
|
|||
import { AddCustomTelemetryTagsToProject1784000000019 } from '../common/1784000000019-AddCustomTelemetryTagsToProject';
|
||||
import { CreateWorkflowPublicationOutboxTable1784000000020 } from '../common/1784000000020-CreateWorkflowPublicationOutboxTable';
|
||||
import { CreateAgentTaskDefinitionTable1784000000021 } from '../common/1784000000021-CreateAgentTaskDefinitionTable';
|
||||
import { AddSubAgentLinkageToAgentExecutionThreads1784000000022 } from '../common/1784000000022-AddSubAgentLinkageToAgentExecutionThreads';
|
||||
import type { Migration } from '../migration-types';
|
||||
|
||||
export const postgresMigrations: Migration[] = [
|
||||
|
|
@ -399,4 +400,5 @@ export const postgresMigrations: Migration[] = [
|
|||
AddCustomTelemetryTagsToProject1784000000019,
|
||||
CreateWorkflowPublicationOutboxTable1784000000020,
|
||||
CreateAgentTaskDefinitionTable1784000000021,
|
||||
AddSubAgentLinkageToAgentExecutionThreads1784000000022,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ import { AddLastUsedAtToApiKey1784000000017 } from '../common/1784000000017-AddL
|
|||
import { CreateAgentFilesTable1784000000018 } from '../common/1784000000018-CreateAgentFilesTable';
|
||||
import { AddCustomTelemetryTagsToProject1784000000019 } from '../common/1784000000019-AddCustomTelemetryTagsToProject';
|
||||
import { CreateWorkflowPublicationOutboxTable1784000000020 } from '../common/1784000000020-CreateWorkflowPublicationOutboxTable';
|
||||
import { AddSubAgentLinkageToAgentExecutionThreads1784000000022 } from '../common/1784000000022-AddSubAgentLinkageToAgentExecutionThreads';
|
||||
import type { Migration } from '../migration-types';
|
||||
import { CreateAgentTaskDefinitionTable1784000000021 } from './1784000000021-CreateAgentTaskDefinitionTable';
|
||||
|
||||
|
|
@ -385,6 +386,7 @@ const sqliteMigrations: Migration[] = [
|
|||
AddCustomTelemetryTagsToProject1784000000019,
|
||||
CreateWorkflowPublicationOutboxTable1784000000020,
|
||||
CreateAgentTaskDefinitionTable1784000000021,
|
||||
AddSubAgentLinkageToAgentExecutionThreads1784000000022,
|
||||
];
|
||||
|
||||
export { sqliteMigrations };
|
||||
|
|
|
|||
|
|
@ -40,6 +40,17 @@ export class AgentExecutionThread extends WithTimestampsAndStringId {
|
|||
@Column({ type: 'varchar', length: 8, nullable: true })
|
||||
emoji: string | null;
|
||||
|
||||
/**
|
||||
* Parent session thread id that delegated this run, for navigating back to
|
||||
* it. Holds another thread's id, so it matches the id column width (128).
|
||||
*/
|
||||
@Column({ type: 'varchar', length: 128, nullable: true })
|
||||
parentThreadId: string | null;
|
||||
|
||||
/** Saved agent id of the parent that delegated this run. */
|
||||
@Column({ type: 'varchar', length: 36, nullable: true })
|
||||
parentAgentId: string | null;
|
||||
|
||||
@ManyToOne(() => Project, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'projectId' })
|
||||
project: Project;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,10 @@ export class AgentExecution extends WithTimestampsAndStringId {
|
|||
@JoinColumn({ name: 'threadId' })
|
||||
thread: AgentExecutionThread;
|
||||
|
||||
@Column({ type: 'varchar', length: 36 })
|
||||
// Thread ids are scoped with prefixes/user ids on some surfaces (e.g.
|
||||
// `test-<agentId>:<userId>`), so they exceed a bare uuid — widened to 128 in
|
||||
// AddSubAgentLinkageToAgentExecutionThreads1784000000022.
|
||||
@Column({ type: 'varchar', length: 128 })
|
||||
threadId: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 16 })
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user