From f1fecf97e98b11e9aed8fcedfa2c9a2c031b5bb3 Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Tue, 13 Oct 2026 19:03:23 +0000 Subject: [PATCH] feat(core): Add skills hub tables (no-changelog) (#40464) --- docs/generated/postgres-schema/README.md | 58 ++++ .../postgres-schema/public.agent_history.md | 9 +- .../public.agent_skill_dependency.md | 88 ++++++ .../public.agent_version_skill_dependency.md | 85 ++++++ .../postgres-schema/public.agents.md | 19 +- .../postgres-schema/public.project.md | 12 +- .../generated/postgres-schema/public.skill.md | 131 +++++++++ .../postgres-schema/public.skill_file.md | 62 ++++ .../postgres-schema/public.skill_version.md | 118 ++++++++ docs/generated/postgres-schema/public.user.md | 26 +- docs/generated/sqlite-schema/README.md | 58 ++++ docs/generated/sqlite-schema/agent_history.md | 9 +- .../sqlite-schema/agent_skill_dependency.md | 98 +++++++ .../agent_version_skill_dependency.md | 94 +++++++ docs/generated/sqlite-schema/agents.md | 19 +- docs/generated/sqlite-schema/project.md | 12 +- docs/generated/sqlite-schema/skill.md | 139 +++++++++ docs/generated/sqlite-schema/skill_file.md | 70 +++++ docs/generated/sqlite-schema/skill_version.md | 121 ++++++++ docs/generated/sqlite-schema/user.md | 26 +- .../1791818723687-CreateSkillsHubTables.ts | 197 +++++++++++++ .../cli/src/modules/agents/agents.module.ts | 12 + .../entities/agent-skill-dependency.entity.ts | 20 ++ .../agent-version-skill-dependency.entity.ts | 17 ++ .../agents/entities/skill-file.entity.ts | 15 + .../agents/entities/skill-version.entity.ts | 49 ++++ .../modules/agents/entities/skill.entity.ts | 31 ++ .../ownership-transfer.manifest.json | 5 + ...818723687-create-skills-hub-tables.test.ts | 265 ++++++++++++++++++ 29 files changed, 1857 insertions(+), 8 deletions(-) create mode 100644 docs/generated/postgres-schema/public.agent_skill_dependency.md create mode 100644 docs/generated/postgres-schema/public.agent_version_skill_dependency.md create mode 100644 docs/generated/postgres-schema/public.skill.md create mode 100644 docs/generated/postgres-schema/public.skill_file.md create mode 100644 docs/generated/postgres-schema/public.skill_version.md create mode 100644 docs/generated/sqlite-schema/agent_skill_dependency.md create mode 100644 docs/generated/sqlite-schema/agent_version_skill_dependency.md create mode 100644 docs/generated/sqlite-schema/skill.md create mode 100644 docs/generated/sqlite-schema/skill_file.md create mode 100644 docs/generated/sqlite-schema/skill_version.md create mode 100644 packages/@n8n/db/src/migrations/common/1791818723687-CreateSkillsHubTables.ts create mode 100644 packages/cli/src/modules/agents/entities/agent-skill-dependency.entity.ts create mode 100644 packages/cli/src/modules/agents/entities/agent-version-skill-dependency.entity.ts create mode 100644 packages/cli/src/modules/agents/entities/skill-file.entity.ts create mode 100644 packages/cli/src/modules/agents/entities/skill-version.entity.ts create mode 100644 packages/cli/src/modules/agents/entities/skill.entity.ts create mode 100644 packages/cli/test/migration/1791818723687-create-skills-hub-tables.test.ts diff --git a/docs/generated/postgres-schema/README.md b/docs/generated/postgres-schema/README.md index cdb7a6648cb..8f6c07493fb 100644 --- a/docs/generated/postgres-schema/README.md +++ b/docs/generated/postgres-schema/README.md @@ -29,10 +29,12 @@ Auto-generated from the PostgreSQL migrations in @n8n/db. Do not edit by hand. | [public.agent_message_queue](public.agent_message_queue.md) | 10 | | BASE TABLE | | [public.agent_plan](public.agent_plan.md) | 8 | | BASE TABLE | | [public.agent_plan_history](public.agent_plan_history.md) | 6 | | BASE TABLE | +| [public.agent_skill_dependency](public.agent_skill_dependency.md) | 4 | | BASE TABLE | | [public.agent_task_definition](public.agent_task_definition.md) | 8 | | BASE TABLE | | [public.agent_task_run_lock](public.agent_task_run_lock.md) | 6 | | BASE TABLE | | [public.agent_task_snapshot](public.agent_task_snapshot.md) | 9 | | BASE TABLE | | [public.agent_thread_grants](public.agent_thread_grants.md) | 4 | | BASE TABLE | +| [public.agent_version_skill_dependency](public.agent_version_skill_dependency.md) | 4 | | BASE TABLE | | [public.agent_workflow_dependency](public.agent_workflow_dependency.md) | 3 | | BASE TABLE | | [public.agents](public.agents.md) | 14 | | BASE TABLE | | [public.agents_memory_entries](public.agents_memory_entries.md) | 13 | | BASE TABLE | @@ -131,6 +133,9 @@ Auto-generated from the PostgreSQL migrations in @n8n/db. Do not edit by hand. | [public.settings](public.settings.md) | 3 | | BASE TABLE | | [public.shared_credentials](public.shared_credentials.md) | 5 | | BASE TABLE | | [public.shared_workflow](public.shared_workflow.md) | 5 | | BASE TABLE | +| [public.skill](public.skill.md) | 7 | | BASE TABLE | +| [public.skill_file](public.skill_file.md) | 5 | | BASE TABLE | +| [public.skill_version](public.skill_version.md) | 11 | | BASE TABLE | | [public.tag_entity](public.tag_entity.md) | 4 | | BASE TABLE | | [public.test_case_execution](public.test_case_execution.md) | 14 | | BASE TABLE | | [public.test_run](public.test_run.md) | 16 | | BASE TABLE | @@ -223,10 +228,16 @@ erDiagram "public.agent_message_queue" }o--|| "public.agent_execution_threads" : "FOREIGN KEY (#quot;threadId#quot;) REFERENCES agent_execution_threads(id) ON DELETE CASCADE" "public.agent_plan" }o--|| "public.agent_execution_threads" : "FOREIGN KEY (#quot;threadId#quot;) REFERENCES agent_execution_threads(id) ON DELETE CASCADE" "public.agent_plan_history" }o--|| "public.agent_plan" : "FOREIGN KEY (#quot;planId#quot;) REFERENCES agent_plan(id) ON DELETE CASCADE" +"public.agent_skill_dependency" }o--|| "public.agents" : "FOREIGN KEY (#quot;agentId#quot;) REFERENCES agents(id) ON DELETE CASCADE" +"public.agent_skill_dependency" }o--|| "public.skill" : "FOREIGN KEY (#quot;skillId#quot;) REFERENCES skill(id) ON DELETE CASCADE" +"public.agent_skill_dependency" }o--o| "public.skill_version" : "FOREIGN KEY (#quot;skillVersionId#quot;) REFERENCES skill_version(id)" "public.agent_task_definition" }o--|| "public.agents" : "FOREIGN KEY (#quot;agentId#quot;) REFERENCES agents(id) ON DELETE CASCADE" "public.agent_task_run_lock" }o--|| "public.agents" : "FOREIGN KEY (#quot;agentId#quot;) REFERENCES agents(id) ON DELETE CASCADE" "public.agent_task_snapshot" }o--|| "public.agent_history" : "FOREIGN KEY (#quot;versionId#quot;) REFERENCES agent_history(#quot;versionId#quot;) ON DELETE CASCADE" "public.agent_thread_grants" }o--|| "public.agent_execution_threads" : "FOREIGN KEY (#quot;threadId#quot;) REFERENCES agent_execution_threads(id) ON DELETE CASCADE" +"public.agent_version_skill_dependency" }o--|| "public.agent_history" : "FOREIGN KEY (#quot;agentVersionId#quot;) REFERENCES agent_history(#quot;versionId#quot;) ON DELETE CASCADE" +"public.agent_version_skill_dependency" }o--|| "public.skill" : "FOREIGN KEY (#quot;skillId#quot;) REFERENCES skill(id) ON DELETE CASCADE" +"public.agent_version_skill_dependency" }o--|| "public.skill_version" : "FOREIGN KEY (#quot;skillVersionId#quot;) REFERENCES skill_version(id)" "public.agent_workflow_dependency" }o--|| "public.workflow_entity" : "FOREIGN KEY (#quot;workflowId#quot;) REFERENCES workflow_entity(id) ON DELETE CASCADE" "public.agent_workflow_dependency" }o--|| "public.agents" : "FOREIGN KEY (#quot;agentId#quot;) REFERENCES agents(id) ON DELETE CASCADE" "public.agents" }o--|| "public.project" : "FOREIGN KEY (#quot;projectId#quot;) REFERENCES project(id) ON DELETE CASCADE" @@ -369,6 +380,12 @@ erDiagram "public.shared_credentials" }o--|| "public.project" : "FOREIGN KEY (#quot;projectId#quot;) REFERENCES project(id) ON DELETE CASCADE" "public.shared_workflow" }o--|| "public.workflow_entity" : "FOREIGN KEY (#quot;workflowId#quot;) REFERENCES workflow_entity(id) ON DELETE CASCADE" "public.shared_workflow" }o--|| "public.project" : "FOREIGN KEY (#quot;projectId#quot;) REFERENCES project(id) ON DELETE CASCADE" +"public.skill" }o--o| "public.user" : "FOREIGN KEY (#quot;createdById#quot;) REFERENCES #quot;user#quot;(id) ON DELETE SET NULL" +"public.skill" }o--o| "public.project" : "FOREIGN KEY (#quot;projectId#quot;) REFERENCES project(id) ON DELETE CASCADE" +"public.skill" }o--o| "public.agents" : "FOREIGN KEY (#quot;agentId#quot;) REFERENCES agents(id) ON DELETE CASCADE" +"public.skill_file" }o--|| "public.skill_version" : "FOREIGN KEY (#quot;skillVersionId#quot;) REFERENCES skill_version(id) ON DELETE CASCADE" +"public.skill_version" }o--o| "public.user" : "FOREIGN KEY (#quot;createdById#quot;) REFERENCES #quot;user#quot;(id) ON DELETE SET NULL" +"public.skill_version" }o--|| "public.skill" : "FOREIGN KEY (#quot;skillId#quot;) REFERENCES skill(id) ON DELETE CASCADE" "public.test_case_execution" }o--o| "public.execution_entity" : "FOREIGN KEY (#quot;executionId#quot;) REFERENCES execution_entity(id) ON DELETE SET NULL" "public.test_case_execution" }o--|| "public.test_run" : "FOREIGN KEY (#quot;testRunId#quot;) REFERENCES test_run(id) ON DELETE CASCADE" "public.test_run" }o--|| "public.workflow_entity" : "FOREIGN KEY (#quot;workflowId#quot;) REFERENCES workflow_entity(id) ON DELETE CASCADE" @@ -679,6 +696,12 @@ erDiagram uuid planId FK integer revision } +"public.agent_skill_dependency" { + varchar_36_ agentId FK + timestamp_3__with_time_zone createdAt + varchar_36_ skillId FK + uuid skillVersionId FK +} "public.agent_task_definition" { varchar_36_ agentId FK timestamp_3__with_time_zone createdAt @@ -714,6 +737,12 @@ erDiagram varchar_128_ threadId FK timestamp_3__with_time_zone updatedAt } +"public.agent_version_skill_dependency" { + varchar_36_ agentVersionId FK + timestamp_3__with_time_zone createdAt + varchar_36_ skillId FK + uuid skillVersionId FK +} "public.agent_workflow_dependency" { varchar_36_ agentId FK timestamp_3__with_time_zone createdAt @@ -1651,6 +1680,35 @@ erDiagram timestamp_3__with_time_zone updatedAt varchar_36_ workflowId FK } +"public.skill" { + varchar_36_ agentId FK + timestamp_3__with_time_zone createdAt + uuid createdById FK + varchar_36_ id + varchar_36_ projectId FK + varchar_16_ source + timestamp_3__with_time_zone updatedAt +} +"public.skill_file" { + text content + timestamp_3__with_time_zone createdAt + varchar_512_ path + uuid skillVersionId FK + timestamp_3__with_time_zone updatedAt +} +"public.skill_version" { + varchar_64_ contentHash + timestamp_3__with_time_zone createdAt + uuid createdById FK + varchar_1024_ description + json frontmatter + uuid id + text instructions + varchar_128_ name + varchar_36_ skillId FK + timestamp_3__with_time_zone updatedAt + integer version +} "public.tag_entity" { timestamp_3__with_time_zone createdAt varchar_36_ id diff --git a/docs/generated/postgres-schema/public.agent_history.md b/docs/generated/postgres-schema/public.agent_history.md index f04cb3a9138..f88d49c9688 100644 --- a/docs/generated/postgres-schema/public.agent_history.md +++ b/docs/generated/postgres-schema/public.agent_history.md @@ -12,7 +12,7 @@ | skills | json | | true | | | Frozen map of `skillId → AgentSkill` at publish time | | tools | json | | true | | | Frozen map of `toolId → { code, descriptor }` at publish time | | updatedAt | timestamp(3) with time zone | CURRENT_TIMESTAMP(3) | false | | | | -| versionId | varchar(36) | | false | [public.agent_execution_threads](public.agent_execution_threads.md) [public.agent_task_snapshot](public.agent_task_snapshot.md) [public.agents](public.agents.md) | | | +| versionId | varchar(36) | | false | [public.agent_execution_threads](public.agent_execution_threads.md) [public.agent_task_snapshot](public.agent_task_snapshot.md) [public.agent_version_skill_dependency](public.agent_version_skill_dependency.md) [public.agents](public.agents.md) | | | ## Constraints @@ -43,6 +43,7 @@ erDiagram "public.agent_history" }o--o| "public.user" : "FOREIGN KEY (#quot;publishedById#quot;) REFERENCES #quot;user#quot;(id) ON DELETE SET NULL" "public.agent_execution_threads" }o--o| "public.agent_history" : "FOREIGN KEY (#quot;taskVersionId#quot;) REFERENCES agent_history(#quot;versionId#quot;) ON DELETE SET NULL" "public.agent_task_snapshot" }o--|| "public.agent_history" : "FOREIGN KEY (#quot;versionId#quot;) REFERENCES agent_history(#quot;versionId#quot;) ON DELETE CASCADE" +"public.agent_version_skill_dependency" }o--|| "public.agent_history" : "FOREIGN KEY (#quot;agentVersionId#quot;) REFERENCES agent_history(#quot;versionId#quot;) ON DELETE CASCADE" "public.agents" }o--o| "public.agent_history" : "FOREIGN KEY (#quot;activeVersionId#quot;) REFERENCES agent_history(#quot;versionId#quot;) ON DELETE SET NULL" "public.agent_history" { @@ -121,6 +122,12 @@ erDiagram timestamp_3__with_time_zone updatedAt varchar_36_ versionId FK } +"public.agent_version_skill_dependency" { + varchar_36_ agentVersionId FK + timestamp_3__with_time_zone createdAt + varchar_36_ skillId FK + uuid skillVersionId FK +} ``` --- diff --git a/docs/generated/postgres-schema/public.agent_skill_dependency.md b/docs/generated/postgres-schema/public.agent_skill_dependency.md new file mode 100644 index 00000000000..b799959e324 --- /dev/null +++ b/docs/generated/postgres-schema/public.agent_skill_dependency.md @@ -0,0 +1,88 @@ +# public.agent_skill_dependency + +## Columns + +| Name | Type | Default | Nullable | Children | Parents | Comment | +| ---- | ---- | ------- | -------- | -------- | ------- | ------- | +| agentId | varchar(36) | | false | | [public.agents](public.agents.md) | | +| createdAt | timestamp(3) with time zone | CURRENT_TIMESTAMP(3) | false | | | | +| skillId | varchar(36) | | false | | [public.skill](public.skill.md) | | +| skillVersionId | uuid | | true | | [public.skill_version](public.skill_version.md) | Set when the agent draft pins a saved version. NULL = follows the latest saved version | + +## Constraints + +| Name | Type | Definition | +| ---- | ---- | ---------- | +| FK_068f21aefba31ae621482f396dc | FOREIGN KEY | FOREIGN KEY ("skillId") REFERENCES skill(id) ON DELETE CASCADE | +| FK_72325bb13511a51847c53fcb377 | FOREIGN KEY | FOREIGN KEY ("agentId") REFERENCES agents(id) ON DELETE CASCADE | +| FK_7676571bd6f41d9e32f0d066fe9 | FOREIGN KEY | FOREIGN KEY ("skillVersionId") REFERENCES skill_version(id) | +| PK_18a54f60491d3e2aa2200b70f4a | PRIMARY KEY | PRIMARY KEY ("agentId", "skillId") | +| agent_skill_dependency_agentId_not_null | n | NOT NULL "agentId" | +| agent_skill_dependency_createdAt_not_null | n | NOT NULL "createdAt" | +| agent_skill_dependency_skillId_not_null | n | NOT NULL "skillId" | + +## Indexes + +| Name | Definition | +| ---- | ---------- | +| IDX_068f21aefba31ae621482f396d | CREATE INDEX "IDX_068f21aefba31ae621482f396d" ON public.agent_skill_dependency USING btree ("skillId") | +| PK_18a54f60491d3e2aa2200b70f4a | CREATE UNIQUE INDEX "PK_18a54f60491d3e2aa2200b70f4a" ON public.agent_skill_dependency USING btree ("agentId", "skillId") | + +## Relations + +```mermaid +erDiagram + +"public.agent_skill_dependency" }o--|| "public.agents" : "FOREIGN KEY (#quot;agentId#quot;) REFERENCES agents(id) ON DELETE CASCADE" +"public.agent_skill_dependency" }o--|| "public.skill" : "FOREIGN KEY (#quot;skillId#quot;) REFERENCES skill(id) ON DELETE CASCADE" +"public.agent_skill_dependency" }o--o| "public.skill_version" : "FOREIGN KEY (#quot;skillVersionId#quot;) REFERENCES skill_version(id)" + +"public.agent_skill_dependency" { + varchar_36_ agentId FK + timestamp_3__with_time_zone createdAt + varchar_36_ skillId FK + uuid skillVersionId FK +} +"public.agents" { + varchar_36_ activeVersionId FK + boolean availableInMCP + timestamp_3__with_time_zone createdAt + varchar_36_ id + json integrations + varchar_128_ name + varchar_255_ projectId FK + integer revision + json schema + timestamp_3__with_time_zone setupCompletedAt + json skills + json tools + timestamp_3__with_time_zone updatedAt + varchar_36_ versionId +} +"public.skill" { + varchar_36_ agentId FK + timestamp_3__with_time_zone createdAt + uuid createdById FK + varchar_36_ id + varchar_36_ projectId FK + varchar_16_ source + timestamp_3__with_time_zone updatedAt +} +"public.skill_version" { + varchar_64_ contentHash + timestamp_3__with_time_zone createdAt + uuid createdById FK + varchar_1024_ description + json frontmatter + uuid id + text instructions + varchar_128_ name + varchar_36_ skillId FK + timestamp_3__with_time_zone updatedAt + integer version +} +``` + +--- + +> Generated by [tbls](https://github.com/k1LoW/tbls) diff --git a/docs/generated/postgres-schema/public.agent_version_skill_dependency.md b/docs/generated/postgres-schema/public.agent_version_skill_dependency.md new file mode 100644 index 00000000000..4135311d27d --- /dev/null +++ b/docs/generated/postgres-schema/public.agent_version_skill_dependency.md @@ -0,0 +1,85 @@ +# public.agent_version_skill_dependency + +## Columns + +| Name | Type | Default | Nullable | Children | Parents | Comment | +| ---- | ---- | ------- | -------- | -------- | ------- | ------- | +| agentVersionId | varchar(36) | | false | | [public.agent_history](public.agent_history.md) | | +| createdAt | timestamp(3) with time zone | CURRENT_TIMESTAMP(3) | false | | | | +| skillId | varchar(36) | | false | | [public.skill](public.skill.md) | | +| skillVersionId | uuid | | false | | [public.skill_version](public.skill_version.md) | | + +## Constraints + +| Name | Type | Definition | +| ---- | ---- | ---------- | +| FK_97472baf9196d914d9cd9de6201 | FOREIGN KEY | FOREIGN KEY ("agentVersionId") REFERENCES agent_history("versionId") ON DELETE CASCADE | +| FK_c494292243a7e510acd0331c3d1 | FOREIGN KEY | FOREIGN KEY ("skillId") REFERENCES skill(id) ON DELETE CASCADE | +| FK_df63badfd7d3f2aa622ece471c4 | FOREIGN KEY | FOREIGN KEY ("skillVersionId") REFERENCES skill_version(id) | +| PK_df0a2577371b94f3c7008d81822 | PRIMARY KEY | PRIMARY KEY ("agentVersionId", "skillId") | +| agent_version_skill_dependency_agentVersionId_not_null | n | NOT NULL "agentVersionId" | +| agent_version_skill_dependency_createdAt_not_null | n | NOT NULL "createdAt" | +| agent_version_skill_dependency_skillId_not_null | n | NOT NULL "skillId" | +| agent_version_skill_dependency_skillVersionId_not_null | n | NOT NULL "skillVersionId" | + +## Indexes + +| Name | Definition | +| ---- | ---------- | +| IDX_c494292243a7e510acd0331c3d | CREATE INDEX "IDX_c494292243a7e510acd0331c3d" ON public.agent_version_skill_dependency USING btree ("skillId") | +| IDX_df63badfd7d3f2aa622ece471c | CREATE INDEX "IDX_df63badfd7d3f2aa622ece471c" ON public.agent_version_skill_dependency USING btree ("skillVersionId") | +| PK_df0a2577371b94f3c7008d81822 | CREATE UNIQUE INDEX "PK_df0a2577371b94f3c7008d81822" ON public.agent_version_skill_dependency USING btree ("agentVersionId", "skillId") | + +## Relations + +```mermaid +erDiagram + +"public.agent_version_skill_dependency" }o--|| "public.agent_history" : "FOREIGN KEY (#quot;agentVersionId#quot;) REFERENCES agent_history(#quot;versionId#quot;) ON DELETE CASCADE" +"public.agent_version_skill_dependency" }o--|| "public.skill" : "FOREIGN KEY (#quot;skillId#quot;) REFERENCES skill(id) ON DELETE CASCADE" +"public.agent_version_skill_dependency" }o--|| "public.skill_version" : "FOREIGN KEY (#quot;skillVersionId#quot;) REFERENCES skill_version(id)" + +"public.agent_version_skill_dependency" { + varchar_36_ agentVersionId FK + timestamp_3__with_time_zone createdAt + varchar_36_ skillId FK + uuid skillVersionId FK +} +"public.agent_history" { + varchar_36_ agentId FK + varchar_255_ author + timestamp_3__with_time_zone createdAt + uuid publishedById FK + json schema + json skills + json tools + timestamp_3__with_time_zone updatedAt + varchar_36_ versionId +} +"public.skill" { + varchar_36_ agentId FK + timestamp_3__with_time_zone createdAt + uuid createdById FK + varchar_36_ id + varchar_36_ projectId FK + varchar_16_ source + timestamp_3__with_time_zone updatedAt +} +"public.skill_version" { + varchar_64_ contentHash + timestamp_3__with_time_zone createdAt + uuid createdById FK + varchar_1024_ description + json frontmatter + uuid id + text instructions + varchar_128_ name + varchar_36_ skillId FK + timestamp_3__with_time_zone updatedAt + integer version +} +``` + +--- + +> Generated by [tbls](https://github.com/k1LoW/tbls) diff --git a/docs/generated/postgres-schema/public.agents.md b/docs/generated/postgres-schema/public.agents.md index 3d52647188f..63aa85de828 100644 --- a/docs/generated/postgres-schema/public.agents.md +++ b/docs/generated/postgres-schema/public.agents.md @@ -7,7 +7,7 @@ | activeVersionId | varchar(36) | | true | | [public.agent_history](public.agent_history.md) | | | availableInMCP | boolean | false | false | | | Whether MCP clients granted agent scopes may operate on this agent | | createdAt | timestamp(3) with time zone | CURRENT_TIMESTAMP(3) | false | | | | -| id | varchar(36) | | false | [public.agent_background_job](public.agent_background_job.md) [public.agent_channel_status](public.agent_channel_status.md) [public.agent_chat_attachments](public.agent_chat_attachments.md) [public.agent_chat_subscriptions](public.agent_chat_subscriptions.md) [public.agent_checkpoints](public.agent_checkpoints.md) [public.agent_credential_dependency](public.agent_credential_dependency.md) [public.agent_eval_dataset](public.agent_eval_dataset.md) [public.agent_execution_threads](public.agent_execution_threads.md) [public.agent_files](public.agent_files.md) [public.agent_history](public.agent_history.md) [public.agent_task_definition](public.agent_task_definition.md) [public.agent_task_run_lock](public.agent_task_run_lock.md) [public.agent_workflow_dependency](public.agent_workflow_dependency.md) [public.agents_memory_entries](public.agents_memory_entries.md) [public.agents_memory_entry_candidates](public.agents_memory_entry_candidates.md) [public.agents_memory_entry_locks](public.agents_memory_entry_locks.md) [public.agents_memory_entry_sources](public.agents_memory_entry_sources.md) [public.agents_observation_cursors](public.agents_observation_cursors.md) [public.agents_observation_locks](public.agents_observation_locks.md) [public.agents_observations](public.agents_observations.md) | | | +| id | varchar(36) | | false | [public.agent_background_job](public.agent_background_job.md) [public.agent_channel_status](public.agent_channel_status.md) [public.agent_chat_attachments](public.agent_chat_attachments.md) [public.agent_chat_subscriptions](public.agent_chat_subscriptions.md) [public.agent_checkpoints](public.agent_checkpoints.md) [public.agent_credential_dependency](public.agent_credential_dependency.md) [public.agent_eval_dataset](public.agent_eval_dataset.md) [public.agent_execution_threads](public.agent_execution_threads.md) [public.agent_files](public.agent_files.md) [public.agent_history](public.agent_history.md) [public.agent_skill_dependency](public.agent_skill_dependency.md) [public.agent_task_definition](public.agent_task_definition.md) [public.agent_task_run_lock](public.agent_task_run_lock.md) [public.agent_workflow_dependency](public.agent_workflow_dependency.md) [public.agents_memory_entries](public.agents_memory_entries.md) [public.agents_memory_entry_candidates](public.agents_memory_entry_candidates.md) [public.agents_memory_entry_locks](public.agents_memory_entry_locks.md) [public.agents_memory_entry_sources](public.agents_memory_entry_sources.md) [public.agents_observation_cursors](public.agents_observation_cursors.md) [public.agents_observation_locks](public.agents_observation_locks.md) [public.agents_observations](public.agents_observations.md) [public.skill](public.skill.md) | | | | integrations | json | '[]'::json | false | | | | | name | varchar(128) | | false | | | | | projectId | varchar(255) | | false | | [public.project](public.project.md) | | @@ -61,6 +61,7 @@ erDiagram "public.agent_execution_threads" }o--|| "public.agents" : "FOREIGN KEY (#quot;agentId#quot;) REFERENCES agents(id) ON DELETE CASCADE" "public.agent_files" }o--|| "public.agents" : "FOREIGN KEY (#quot;agentId#quot;) REFERENCES agents(id) ON DELETE CASCADE" "public.agent_history" }o--|| "public.agents" : "FOREIGN KEY (#quot;agentId#quot;) REFERENCES agents(id) ON DELETE CASCADE" +"public.agent_skill_dependency" }o--|| "public.agents" : "FOREIGN KEY (#quot;agentId#quot;) REFERENCES agents(id) ON DELETE CASCADE" "public.agent_task_definition" }o--|| "public.agents" : "FOREIGN KEY (#quot;agentId#quot;) REFERENCES agents(id) ON DELETE CASCADE" "public.agent_task_run_lock" }o--|| "public.agents" : "FOREIGN KEY (#quot;agentId#quot;) REFERENCES agents(id) ON DELETE CASCADE" "public.agent_workflow_dependency" }o--|| "public.agents" : "FOREIGN KEY (#quot;agentId#quot;) REFERENCES agents(id) ON DELETE CASCADE" @@ -71,6 +72,7 @@ erDiagram "public.agents_observation_cursors" }o--|| "public.agents" : "FOREIGN KEY (#quot;agentId#quot;) REFERENCES agents(id) ON DELETE CASCADE" "public.agents_observation_locks" }o--|| "public.agents" : "FOREIGN KEY (#quot;agentId#quot;) REFERENCES agents(id) ON DELETE CASCADE" "public.agents_observations" }o--|| "public.agents" : "FOREIGN KEY (#quot;agentId#quot;) REFERENCES agents(id) ON DELETE CASCADE" +"public.skill" }o--o| "public.agents" : "FOREIGN KEY (#quot;agentId#quot;) REFERENCES agents(id) ON DELETE CASCADE" "public.agents" }o--|| "public.project" : "FOREIGN KEY (#quot;projectId#quot;) REFERENCES project(id) ON DELETE CASCADE" "public.agents" { @@ -216,6 +218,12 @@ erDiagram varchar_2_ storedAt timestamp_3__with_time_zone updatedAt } +"public.agent_skill_dependency" { + varchar_36_ agentId FK + timestamp_3__with_time_zone createdAt + varchar_36_ skillId FK + uuid skillVersionId FK +} "public.agent_task_definition" { varchar_36_ agentId FK timestamp_3__with_time_zone createdAt @@ -320,6 +328,15 @@ erDiagram integer tokenCount timestamp_3__with_time_zone updatedAt } +"public.skill" { + varchar_36_ agentId FK + timestamp_3__with_time_zone createdAt + uuid createdById FK + varchar_36_ id + varchar_36_ projectId FK + varchar_16_ source + timestamp_3__with_time_zone updatedAt +} "public.project" { timestamp_3__with_time_zone createdAt uuid creatorId FK diff --git a/docs/generated/postgres-schema/public.project.md b/docs/generated/postgres-schema/public.project.md index 670547327f1..04d30b4ff68 100644 --- a/docs/generated/postgres-schema/public.project.md +++ b/docs/generated/postgres-schema/public.project.md @@ -9,7 +9,7 @@ | customTelemetryTags | json | '[]'::json | false | | | | | description | varchar(512) | | true | | | | | icon | json | | true | | | | -| id | varchar(36) | | false | [public.activity_event](public.activity_event.md) [public.agent_chat_attachments](public.agent_chat_attachments.md) [public.agent_execution_threads](public.agent_execution_threads.md) [public.agents](public.agents.md) [public.ai_preference](public.ai_preference.md) [public.data_table](public.data_table.md) [public.folder](public.folder.md) [public.insights_metadata](public.insights_metadata.md) [public.instance_ai_threads](public.instance_ai_threads.md) [public.project_pool_settings](public.project_pool_settings.md) [public.project_relation](public.project_relation.md) [public.project_secrets_provider_access](public.project_secrets_provider_access.md) [public.promotion_connection_project](public.promotion_connection_project.md) [public.role_mapping_rule_project](public.role_mapping_rule_project.md) [public.self_healing_result](public.self_healing_result.md) [public.shared_credentials](public.shared_credentials.md) [public.shared_workflow](public.shared_workflow.md) [public.type_availability_policy_scope](public.type_availability_policy_scope.md) [public.variables](public.variables.md) [public.workflow_review_request](public.workflow_review_request.md) [public.workflow_suggestion](public.workflow_suggestion.md) | | | +| id | varchar(36) | | false | [public.activity_event](public.activity_event.md) [public.agent_chat_attachments](public.agent_chat_attachments.md) [public.agent_execution_threads](public.agent_execution_threads.md) [public.agents](public.agents.md) [public.ai_preference](public.ai_preference.md) [public.data_table](public.data_table.md) [public.folder](public.folder.md) [public.insights_metadata](public.insights_metadata.md) [public.instance_ai_threads](public.instance_ai_threads.md) [public.project_pool_settings](public.project_pool_settings.md) [public.project_relation](public.project_relation.md) [public.project_secrets_provider_access](public.project_secrets_provider_access.md) [public.promotion_connection_project](public.promotion_connection_project.md) [public.role_mapping_rule_project](public.role_mapping_rule_project.md) [public.self_healing_result](public.self_healing_result.md) [public.shared_credentials](public.shared_credentials.md) [public.shared_workflow](public.shared_workflow.md) [public.skill](public.skill.md) [public.type_availability_policy_scope](public.type_availability_policy_scope.md) [public.variables](public.variables.md) [public.workflow_review_request](public.workflow_review_request.md) [public.workflow_suggestion](public.workflow_suggestion.md) | | | | name | varchar(255) | | false | | | | | type | varchar(36) | | false | | | | | updatedAt | timestamp(3) with time zone | CURRENT_TIMESTAMP(3) | false | | | | @@ -56,6 +56,7 @@ erDiagram "public.self_healing_result" }o--|| "public.project" : "FOREIGN KEY (#quot;projectId#quot;) REFERENCES project(id) ON DELETE CASCADE" "public.shared_credentials" }o--|| "public.project" : "FOREIGN KEY (#quot;projectId#quot;) REFERENCES project(id) ON DELETE CASCADE" "public.shared_workflow" }o--|| "public.project" : "FOREIGN KEY (#quot;projectId#quot;) REFERENCES project(id) ON DELETE CASCADE" +"public.skill" }o--o| "public.project" : "FOREIGN KEY (#quot;projectId#quot;) REFERENCES project(id) ON DELETE CASCADE" "public.type_availability_policy_scope" }o--o| "public.project" : "FOREIGN KEY (#quot;projectId#quot;) REFERENCES project(id) ON DELETE CASCADE" "public.variables" }o--o| "public.project" : "FOREIGN KEY (#quot;projectId#quot;) REFERENCES project(id) ON DELETE CASCADE" "public.workflow_review_request" }o--|| "public.project" : "FOREIGN KEY (#quot;projectId#quot;) REFERENCES project(id) ON DELETE CASCADE" @@ -255,6 +256,15 @@ erDiagram timestamp_3__with_time_zone updatedAt varchar_36_ workflowId FK } +"public.skill" { + varchar_36_ agentId FK + timestamp_3__with_time_zone createdAt + uuid createdById FK + varchar_36_ id + varchar_36_ projectId FK + varchar_16_ source + timestamp_3__with_time_zone updatedAt +} "public.type_availability_policy_scope" { timestamp_3__with_time_zone createdAt varchar_16_ defaultAction diff --git a/docs/generated/postgres-schema/public.skill.md b/docs/generated/postgres-schema/public.skill.md new file mode 100644 index 00000000000..9b424ab5239 --- /dev/null +++ b/docs/generated/postgres-schema/public.skill.md @@ -0,0 +1,131 @@ +# public.skill + +## Columns + +| Name | Type | Default | Nullable | Children | Parents | Comment | +| ---- | ---- | ------- | -------- | -------- | ------- | ------- | +| agentId | varchar(36) | | true | | [public.agents](public.agents.md) | Set when only this agent can use the skill. projectId is then NULL: the agent holds the project | +| createdAt | timestamp(3) with time zone | CURRENT_TIMESTAMP(3) | false | | | | +| createdById | uuid | | true | | [public.user](public.user.md) | Author. NULL after the author is deleted | +| id | varchar(36) | | false | [public.agent_skill_dependency](public.agent_skill_dependency.md) [public.agent_version_skill_dependency](public.agent_version_skill_dependency.md) [public.skill_version](public.skill_version.md) | | skill_\, the same format agents use | +| projectId | varchar(36) | | true | | [public.project](public.project.md) | Set for a project skill, team or personal. NULL otherwise | +| source | varchar(16) | | false | | | How the skill was created, set by the server: "ui" (the skills hub) or "agent" (the agent builder or the copy of agent skills) | +| updatedAt | timestamp(3) with time zone | CURRENT_TIMESTAMP(3) | false | | | | + +## Constraints + +| Name | Type | Definition | +| ---- | ---- | ---------- | +| CHK_skill_single_target | CHECK | CHECK ((("agentId" IS NULL) OR ("projectId" IS NULL))) | +| FK_402ed37bff0d3134f6e782455ed | FOREIGN KEY | FOREIGN KEY ("projectId") REFERENCES project(id) ON DELETE CASCADE | +| FK_4de4501583cd1fcd6f5ea85f547 | FOREIGN KEY | FOREIGN KEY ("createdById") REFERENCES "user"(id) ON DELETE SET NULL | +| FK_7d4fb6af107e507d9a86293cf9d | FOREIGN KEY | FOREIGN KEY ("agentId") REFERENCES agents(id) ON DELETE CASCADE | +| PK_a0d33334424e64fb78dc3ce7196 | PRIMARY KEY | PRIMARY KEY (id) | +| skill_createdAt_not_null | n | NOT NULL "createdAt" | +| skill_id_not_null | n | NOT NULL id | +| skill_source_not_null | n | NOT NULL source | +| skill_updatedAt_not_null | n | NOT NULL "updatedAt" | + +## Indexes + +| Name | Definition | +| ---- | ---------- | +| IDX_402ed37bff0d3134f6e782455e | CREATE INDEX "IDX_402ed37bff0d3134f6e782455e" ON public.skill USING btree ("projectId") | +| IDX_7d4fb6af107e507d9a86293cf9 | CREATE INDEX "IDX_7d4fb6af107e507d9a86293cf9" ON public.skill USING btree ("agentId") | +| PK_a0d33334424e64fb78dc3ce7196 | CREATE UNIQUE INDEX "PK_a0d33334424e64fb78dc3ce7196" ON public.skill USING btree (id) | + +## Relations + +```mermaid +erDiagram + +"public.skill" }o--o| "public.agents" : "FOREIGN KEY (#quot;agentId#quot;) REFERENCES agents(id) ON DELETE CASCADE" +"public.skill" }o--o| "public.user" : "FOREIGN KEY (#quot;createdById#quot;) REFERENCES #quot;user#quot;(id) ON DELETE SET NULL" +"public.agent_skill_dependency" }o--|| "public.skill" : "FOREIGN KEY (#quot;skillId#quot;) REFERENCES skill(id) ON DELETE CASCADE" +"public.agent_version_skill_dependency" }o--|| "public.skill" : "FOREIGN KEY (#quot;skillId#quot;) REFERENCES skill(id) ON DELETE CASCADE" +"public.skill_version" }o--|| "public.skill" : "FOREIGN KEY (#quot;skillId#quot;) REFERENCES skill(id) ON DELETE CASCADE" +"public.skill" }o--o| "public.project" : "FOREIGN KEY (#quot;projectId#quot;) REFERENCES project(id) ON DELETE CASCADE" + +"public.skill" { + varchar_36_ agentId FK + timestamp_3__with_time_zone createdAt + uuid createdById FK + varchar_36_ id + varchar_36_ projectId FK + varchar_16_ source + timestamp_3__with_time_zone updatedAt +} +"public.agents" { + varchar_36_ activeVersionId FK + boolean availableInMCP + timestamp_3__with_time_zone createdAt + varchar_36_ id + json integrations + varchar_128_ name + varchar_255_ projectId FK + integer revision + json schema + timestamp_3__with_time_zone setupCompletedAt + json skills + json tools + timestamp_3__with_time_zone updatedAt + varchar_36_ versionId +} +"public.user" { + timestamp_3__with_time_zone createdAt + boolean disabled + varchar_255_ email + varchar_32_ firstName + uuid id + date lastActiveAt + varchar_32_ lastName + boolean mfaEnabled + text mfaRecoveryCodes + text mfaSecret + varchar_255_ password + json personalizationAnswers + varchar_128_ roleSlug FK + json settings + timestamp_3__with_time_zone updatedAt +} +"public.agent_skill_dependency" { + varchar_36_ agentId FK + timestamp_3__with_time_zone createdAt + varchar_36_ skillId FK + uuid skillVersionId FK +} +"public.agent_version_skill_dependency" { + varchar_36_ agentVersionId FK + timestamp_3__with_time_zone createdAt + varchar_36_ skillId FK + uuid skillVersionId FK +} +"public.skill_version" { + varchar_64_ contentHash + timestamp_3__with_time_zone createdAt + uuid createdById FK + varchar_1024_ description + json frontmatter + uuid id + text instructions + varchar_128_ name + varchar_36_ skillId FK + timestamp_3__with_time_zone updatedAt + integer version +} +"public.project" { + timestamp_3__with_time_zone createdAt + uuid creatorId FK + json customTelemetryTags + varchar_512_ description + json icon + varchar_36_ id + varchar_255_ name + varchar_36_ type + timestamp_3__with_time_zone updatedAt +} +``` + +--- + +> Generated by [tbls](https://github.com/k1LoW/tbls) diff --git a/docs/generated/postgres-schema/public.skill_file.md b/docs/generated/postgres-schema/public.skill_file.md new file mode 100644 index 00000000000..051bcb40661 --- /dev/null +++ b/docs/generated/postgres-schema/public.skill_file.md @@ -0,0 +1,62 @@ +# public.skill_file + +## Columns + +| Name | Type | Default | Nullable | Children | Parents | Comment | +| ---- | ---- | ------- | -------- | -------- | ------- | ------- | +| content | text | | false | | | | +| createdAt | timestamp(3) with time zone | CURRENT_TIMESTAMP(3) | false | | | | +| path | varchar(512) | | false | | | Relative path, references/*.md in v1 | +| skillVersionId | uuid | | false | | [public.skill_version](public.skill_version.md) | | +| updatedAt | timestamp(3) with time zone | CURRENT_TIMESTAMP(3) | false | | | | + +## Constraints + +| Name | Type | Definition | +| ---- | ---- | ---------- | +| FK_e9ab50b795ec8858702b7333d13 | FOREIGN KEY | FOREIGN KEY ("skillVersionId") REFERENCES skill_version(id) ON DELETE CASCADE | +| PK_160721f9e4c22026c16138af2a1 | PRIMARY KEY | PRIMARY KEY ("skillVersionId", path) | +| skill_file_content_not_null | n | NOT NULL content | +| skill_file_createdAt_not_null | n | NOT NULL "createdAt" | +| skill_file_path_not_null | n | NOT NULL path | +| skill_file_skillVersionId_not_null | n | NOT NULL "skillVersionId" | +| skill_file_updatedAt_not_null | n | NOT NULL "updatedAt" | + +## Indexes + +| Name | Definition | +| ---- | ---------- | +| PK_160721f9e4c22026c16138af2a1 | CREATE UNIQUE INDEX "PK_160721f9e4c22026c16138af2a1" ON public.skill_file USING btree ("skillVersionId", path) | + +## Relations + +```mermaid +erDiagram + +"public.skill_file" }o--|| "public.skill_version" : "FOREIGN KEY (#quot;skillVersionId#quot;) REFERENCES skill_version(id) ON DELETE CASCADE" + +"public.skill_file" { + text content + timestamp_3__with_time_zone createdAt + varchar_512_ path + uuid skillVersionId FK + timestamp_3__with_time_zone updatedAt +} +"public.skill_version" { + varchar_64_ contentHash + timestamp_3__with_time_zone createdAt + uuid createdById FK + varchar_1024_ description + json frontmatter + uuid id + text instructions + varchar_128_ name + varchar_36_ skillId FK + timestamp_3__with_time_zone updatedAt + integer version +} +``` + +--- + +> Generated by [tbls](https://github.com/k1LoW/tbls) diff --git a/docs/generated/postgres-schema/public.skill_version.md b/docs/generated/postgres-schema/public.skill_version.md new file mode 100644 index 00000000000..562a13ad867 --- /dev/null +++ b/docs/generated/postgres-schema/public.skill_version.md @@ -0,0 +1,118 @@ +# public.skill_version + +## Columns + +| Name | Type | Default | Nullable | Children | Parents | Comment | +| ---- | ---- | ------- | -------- | -------- | ------- | ------- | +| contentHash | varchar(64) | | false | | | sha256 of name, description, instructions, frontmatter and files. Save creates no version when the content matches the latest one | +| createdAt | timestamp(3) with time zone | CURRENT_TIMESTAMP(3) | false | | | | +| createdById | uuid | | true | | [public.user](public.user.md) | Author. NULL after the author is deleted | +| description | varchar(1024) | | false | | | | +| frontmatter | json | | true | | | SKILL.md frontmatter fields other than name and description, e.g. allowed-tools | +| id | uuid | | false | [public.agent_skill_dependency](public.agent_skill_dependency.md) [public.agent_version_skill_dependency](public.agent_version_skill_dependency.md) [public.skill_file](public.skill_file.md) | | | +| instructions | text | | false | | | | +| name | varchar(128) | | false | | | Free-text skill name, as it was when this version was saved | +| skillId | varchar(36) | | false | | [public.skill](public.skill.md) | | +| updatedAt | timestamp(3) with time zone | CURRENT_TIMESTAMP(3) | false | | | | +| version | integer | | false | | | 1..n per skill. A Save that changes the content adds one; none ever changes | + +## Constraints + +| Name | Type | Definition | +| ---- | ---- | ---------- | +| CHK_skill_version_version | CHECK | CHECK ((version > 0)) | +| FK_9565d0fbf32cd463f9b47c7adab | FOREIGN KEY | FOREIGN KEY ("createdById") REFERENCES "user"(id) ON DELETE SET NULL | +| FK_f87064c0a29efd2d5195328d91a | FOREIGN KEY | FOREIGN KEY ("skillId") REFERENCES skill(id) ON DELETE CASCADE | +| PK_05167d59ac7599128e22400172d | PRIMARY KEY | PRIMARY KEY (id) | +| UQ_93bb78a1eb4e0890fac6b69df95 | UNIQUE | UNIQUE ("skillId", version) | +| skill_version_contentHash_not_null | n | NOT NULL "contentHash" | +| skill_version_createdAt_not_null | n | NOT NULL "createdAt" | +| skill_version_description_not_null | n | NOT NULL description | +| skill_version_id_not_null | n | NOT NULL id | +| skill_version_instructions_not_null | n | NOT NULL instructions | +| skill_version_name_not_null | n | NOT NULL name | +| skill_version_skillId_not_null | n | NOT NULL "skillId" | +| skill_version_updatedAt_not_null | n | NOT NULL "updatedAt" | +| skill_version_version_not_null | n | NOT NULL version | + +## Indexes + +| Name | Definition | +| ---- | ---------- | +| PK_05167d59ac7599128e22400172d | CREATE UNIQUE INDEX "PK_05167d59ac7599128e22400172d" ON public.skill_version USING btree (id) | +| UQ_93bb78a1eb4e0890fac6b69df95 | CREATE UNIQUE INDEX "UQ_93bb78a1eb4e0890fac6b69df95" ON public.skill_version USING btree ("skillId", version) | + +## Relations + +```mermaid +erDiagram + +"public.skill_version" }o--o| "public.user" : "FOREIGN KEY (#quot;createdById#quot;) REFERENCES #quot;user#quot;(id) ON DELETE SET NULL" +"public.agent_skill_dependency" }o--o| "public.skill_version" : "FOREIGN KEY (#quot;skillVersionId#quot;) REFERENCES skill_version(id)" +"public.agent_version_skill_dependency" }o--|| "public.skill_version" : "FOREIGN KEY (#quot;skillVersionId#quot;) REFERENCES skill_version(id)" +"public.skill_file" }o--|| "public.skill_version" : "FOREIGN KEY (#quot;skillVersionId#quot;) REFERENCES skill_version(id) ON DELETE CASCADE" +"public.skill_version" }o--|| "public.skill" : "FOREIGN KEY (#quot;skillId#quot;) REFERENCES skill(id) ON DELETE CASCADE" + +"public.skill_version" { + varchar_64_ contentHash + timestamp_3__with_time_zone createdAt + uuid createdById FK + varchar_1024_ description + json frontmatter + uuid id + text instructions + varchar_128_ name + varchar_36_ skillId FK + timestamp_3__with_time_zone updatedAt + integer version +} +"public.user" { + timestamp_3__with_time_zone createdAt + boolean disabled + varchar_255_ email + varchar_32_ firstName + uuid id + date lastActiveAt + varchar_32_ lastName + boolean mfaEnabled + text mfaRecoveryCodes + text mfaSecret + varchar_255_ password + json personalizationAnswers + varchar_128_ roleSlug FK + json settings + timestamp_3__with_time_zone updatedAt +} +"public.agent_skill_dependency" { + varchar_36_ agentId FK + timestamp_3__with_time_zone createdAt + varchar_36_ skillId FK + uuid skillVersionId FK +} +"public.agent_version_skill_dependency" { + varchar_36_ agentVersionId FK + timestamp_3__with_time_zone createdAt + varchar_36_ skillId FK + uuid skillVersionId FK +} +"public.skill_file" { + text content + timestamp_3__with_time_zone createdAt + varchar_512_ path + uuid skillVersionId FK + timestamp_3__with_time_zone updatedAt +} +"public.skill" { + varchar_36_ agentId FK + timestamp_3__with_time_zone createdAt + uuid createdById FK + varchar_36_ id + varchar_36_ projectId FK + varchar_16_ source + timestamp_3__with_time_zone updatedAt +} +``` + +--- + +> Generated by [tbls](https://github.com/k1LoW/tbls) diff --git a/docs/generated/postgres-schema/public.user.md b/docs/generated/postgres-schema/public.user.md index 2bcc7d1d5e9..8db545537e7 100644 --- a/docs/generated/postgres-schema/public.user.md +++ b/docs/generated/postgres-schema/public.user.md @@ -8,7 +8,7 @@ | disabled | boolean | false | false | | | | | email | varchar(255) | | true | | | | | firstName | varchar(32) | | true | | | | -| id | uuid | gen_random_uuid() | false | [public.activity_event](public.activity_event.md) [public.agent_eval_dataset](public.agent_eval_dataset.md) [public.agent_eval_rating](public.agent_eval_rating.md) [public.agent_eval_run](public.agent_eval_run.md) [public.agent_execution_threads](public.agent_execution_threads.md) [public.agent_history](public.agent_history.md) [public.ai_preference](public.ai_preference.md) [public.auth_identity](public.auth_identity.md) [public.chat_hub_agents](public.chat_hub_agents.md) [public.chat_hub_sessions](public.chat_hub_sessions.md) [public.chat_hub_tools](public.chat_hub_tools.md) [public.dynamic_credential_user_entry](public.dynamic_credential_user_entry.md) [public.evaluation_collection](public.evaluation_collection.md) [public.idempotency_key](public.idempotency_key.md) [public.instance_ai_mcp_registry_connections](public.instance_ai_mcp_registry_connections.md) [public.instance_ai_pending_confirmations](public.instance_ai_pending_confirmations.md) [public.instance_ai_thread_grants](public.instance_ai_thread_grants.md) [public.instance_ai_thread_tabs](public.instance_ai_thread_tabs.md) [public.migration_workflow_owner](public.migration_workflow_owner.md) [public.oauth_access_tokens](public.oauth_access_tokens.md) [public.oauth_authorization_codes](public.oauth_authorization_codes.md) [public.oauth_refresh_tokens](public.oauth_refresh_tokens.md) [public.oauth_user_consents](public.oauth_user_consents.md) [public.project](public.project.md) [public.project_relation](public.project_relation.md) [public.self_healing_result](public.self_healing_result.md) [public.trusted_source_identity](public.trusted_source_identity.md) [public.user_api_keys](public.user_api_keys.md) [public.user_favorites](public.user_favorites.md) [public.workflow_builder_session](public.workflow_builder_session.md) [public.workflow_publish_history](public.workflow_publish_history.md) [public.workflow_review_activity](public.workflow_review_activity.md) [public.workflow_review_activity_comment](public.workflow_review_activity_comment.md) [public.workflow_review_request](public.workflow_review_request.md) [public.workflow_review_request_authors](public.workflow_review_request_authors.md) [public.workflow_review_request_reviewers](public.workflow_review_request_reviewers.md) [public.workflow_suggestion](public.workflow_suggestion.md) [public.workflow_suggestion_activity](public.workflow_suggestion_activity.md) | | | +| id | uuid | gen_random_uuid() | false | [public.activity_event](public.activity_event.md) [public.agent_eval_dataset](public.agent_eval_dataset.md) [public.agent_eval_rating](public.agent_eval_rating.md) [public.agent_eval_run](public.agent_eval_run.md) [public.agent_execution_threads](public.agent_execution_threads.md) [public.agent_history](public.agent_history.md) [public.ai_preference](public.ai_preference.md) [public.auth_identity](public.auth_identity.md) [public.chat_hub_agents](public.chat_hub_agents.md) [public.chat_hub_sessions](public.chat_hub_sessions.md) [public.chat_hub_tools](public.chat_hub_tools.md) [public.dynamic_credential_user_entry](public.dynamic_credential_user_entry.md) [public.evaluation_collection](public.evaluation_collection.md) [public.idempotency_key](public.idempotency_key.md) [public.instance_ai_mcp_registry_connections](public.instance_ai_mcp_registry_connections.md) [public.instance_ai_pending_confirmations](public.instance_ai_pending_confirmations.md) [public.instance_ai_thread_grants](public.instance_ai_thread_grants.md) [public.instance_ai_thread_tabs](public.instance_ai_thread_tabs.md) [public.migration_workflow_owner](public.migration_workflow_owner.md) [public.oauth_access_tokens](public.oauth_access_tokens.md) [public.oauth_authorization_codes](public.oauth_authorization_codes.md) [public.oauth_refresh_tokens](public.oauth_refresh_tokens.md) [public.oauth_user_consents](public.oauth_user_consents.md) [public.project](public.project.md) [public.project_relation](public.project_relation.md) [public.self_healing_result](public.self_healing_result.md) [public.skill](public.skill.md) [public.skill_version](public.skill_version.md) [public.trusted_source_identity](public.trusted_source_identity.md) [public.user_api_keys](public.user_api_keys.md) [public.user_favorites](public.user_favorites.md) [public.workflow_builder_session](public.workflow_builder_session.md) [public.workflow_publish_history](public.workflow_publish_history.md) [public.workflow_review_activity](public.workflow_review_activity.md) [public.workflow_review_activity_comment](public.workflow_review_activity_comment.md) [public.workflow_review_request](public.workflow_review_request.md) [public.workflow_review_request_authors](public.workflow_review_request_authors.md) [public.workflow_review_request_reviewers](public.workflow_review_request_reviewers.md) [public.workflow_suggestion](public.workflow_suggestion.md) [public.workflow_suggestion_activity](public.workflow_suggestion_activity.md) | | | | lastActiveAt | date | | true | | | | | lastName | varchar(32) | | true | | | | | mfaEnabled | boolean | false | false | | | | @@ -76,6 +76,8 @@ erDiagram "public.project_relation" }o--|| "public.user" : "FOREIGN KEY (#quot;userId#quot;) REFERENCES #quot;user#quot;(id) ON DELETE CASCADE" "public.self_healing_result" }o--|| "public.user" : "FOREIGN KEY (#quot;backgroundUserId#quot;) REFERENCES #quot;user#quot;(id) ON DELETE CASCADE" "public.self_healing_result" }o--o| "public.user" : "FOREIGN KEY (#quot;dismissedById#quot;) REFERENCES #quot;user#quot;(id) ON DELETE SET NULL" +"public.skill" }o--o| "public.user" : "FOREIGN KEY (#quot;createdById#quot;) REFERENCES #quot;user#quot;(id) ON DELETE SET NULL" +"public.skill_version" }o--o| "public.user" : "FOREIGN KEY (#quot;createdById#quot;) REFERENCES #quot;user#quot;(id) ON DELETE SET NULL" "public.trusted_source_identity" }o--|| "public.user" : "FOREIGN KEY (#quot;userId#quot;) REFERENCES #quot;user#quot;(id) ON DELETE CASCADE" "public.user_api_keys" }o--|| "public.user" : "FOREIGN KEY (#quot;userId#quot;) REFERENCES #quot;user#quot;(id) ON DELETE CASCADE" "public.user_favorites" }o--|| "public.user" : "FOREIGN KEY (#quot;userId#quot;) REFERENCES #quot;user#quot;(id) ON DELETE CASCADE" @@ -398,6 +400,28 @@ erDiagram json usage varchar_36_ workflowId FK } +"public.skill" { + varchar_36_ agentId FK + timestamp_3__with_time_zone createdAt + uuid createdById FK + varchar_36_ id + varchar_36_ projectId FK + varchar_16_ source + timestamp_3__with_time_zone updatedAt +} +"public.skill_version" { + varchar_64_ contentHash + timestamp_3__with_time_zone createdAt + uuid createdById FK + varchar_1024_ description + json frontmatter + uuid id + text instructions + varchar_128_ name + varchar_36_ skillId FK + timestamp_3__with_time_zone updatedAt + integer version +} "public.trusted_source_identity" { timestamp_3__with_time_zone createdAt timestamp_3__with_time_zone lastSeenAt diff --git a/docs/generated/sqlite-schema/README.md b/docs/generated/sqlite-schema/README.md index c62c719c3f0..6e946dc580d 100644 --- a/docs/generated/sqlite-schema/README.md +++ b/docs/generated/sqlite-schema/README.md @@ -29,10 +29,12 @@ Auto-generated from the SQLite migrations in @n8n/db. Do not edit by hand. | [agent_message_queue](agent_message_queue.md) | 10 | | table | | [agent_plan](agent_plan.md) | 8 | | table | | [agent_plan_history](agent_plan_history.md) | 6 | | table | +| [agent_skill_dependency](agent_skill_dependency.md) | 4 | | table | | [agent_task_definition](agent_task_definition.md) | 8 | | table | | [agent_task_run_lock](agent_task_run_lock.md) | 6 | | table | | [agent_task_snapshot](agent_task_snapshot.md) | 9 | | table | | [agent_thread_grants](agent_thread_grants.md) | 4 | | table | +| [agent_version_skill_dependency](agent_version_skill_dependency.md) | 4 | | table | | [agent_workflow_dependency](agent_workflow_dependency.md) | 3 | | table | | [agents](agents.md) | 14 | | table | | [agents_memory_entries](agents_memory_entries.md) | 13 | | table | @@ -131,6 +133,9 @@ Auto-generated from the SQLite migrations in @n8n/db. Do not edit by hand. | [settings](settings.md) | 3 | | table | | [shared_credentials](shared_credentials.md) | 5 | | table | | [shared_workflow](shared_workflow.md) | 5 | | table | +| [skill](skill.md) | 7 | | table | +| [skill_file](skill_file.md) | 5 | | table | +| [skill_version](skill_version.md) | 11 | | table | | [tag_entity](tag_entity.md) | 4 | | table | | [test_case_execution](test_case_execution.md) | 16 | | table | | [test_run](test_run.md) | 16 | | table | @@ -205,10 +210,16 @@ erDiagram "agent_message_queue" }o--o| "agent_execution" : "FOREIGN KEY (steeringExecutionId) REFERENCES agent_execution (id) ON UPDATE NO ACTION ON DELETE NO ACTION MATCH NONE" "agent_plan" }o--|| "agent_execution_threads" : "FOREIGN KEY (threadId) REFERENCES agent_execution_threads (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "agent_plan_history" |o--|| "agent_plan" : "FOREIGN KEY (planId) REFERENCES agent_plan (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"agent_skill_dependency" }o--o| "skill_version" : "FOREIGN KEY (skillVersionId) REFERENCES skill_version (id) ON UPDATE NO ACTION ON DELETE NO ACTION MATCH NONE" +"agent_skill_dependency" |o--|| "skill" : "FOREIGN KEY (skillId) REFERENCES skill (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"agent_skill_dependency" |o--|| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "agent_task_definition" }o--|| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "agent_task_run_lock" |o--|| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "agent_task_snapshot" |o--|| "agent_history" : "FOREIGN KEY (versionId) REFERENCES agent_history (versionId) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "agent_thread_grants" |o--|| "agent_execution_threads" : "FOREIGN KEY (threadId) REFERENCES agent_execution_threads (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"agent_version_skill_dependency" }o--|| "skill_version" : "FOREIGN KEY (skillVersionId) REFERENCES skill_version (id) ON UPDATE NO ACTION ON DELETE NO ACTION MATCH NONE" +"agent_version_skill_dependency" |o--|| "skill" : "FOREIGN KEY (skillId) REFERENCES skill (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"agent_version_skill_dependency" |o--|| "agent_history" : "FOREIGN KEY (agentVersionId) REFERENCES agent_history (versionId) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "agent_workflow_dependency" |o--|| "workflow_entity" : "FOREIGN KEY (workflowId) REFERENCES workflow_entity (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "agent_workflow_dependency" |o--|| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "agents" }o--|| "project" : "FOREIGN KEY (projectId) REFERENCES project (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" @@ -351,6 +362,12 @@ erDiagram "shared_credentials" |o--|| "credentials_entity" : "FOREIGN KEY (credentialsId) REFERENCES credentials_entity (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "shared_workflow" |o--|| "project" : "FOREIGN KEY (projectId) REFERENCES project (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "shared_workflow" |o--|| "workflow_entity" : "FOREIGN KEY (workflowId) REFERENCES workflow_entity (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"skill" }o--o| "user" : "FOREIGN KEY (createdById) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE SET NULL MATCH NONE" +"skill" }o--o| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"skill" }o--o| "project" : "FOREIGN KEY (projectId) REFERENCES project (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"skill_file" |o--|| "skill_version" : "FOREIGN KEY (skillVersionId) REFERENCES skill_version (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"skill_version" }o--o| "user" : "FOREIGN KEY (createdById) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE SET NULL MATCH NONE" +"skill_version" }o--|| "skill" : "FOREIGN KEY (skillId) REFERENCES skill (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "test_case_execution" }o--|| "test_run" : "FOREIGN KEY (testRunId) REFERENCES test_run (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "test_case_execution" }o--o| "execution_entity" : "FOREIGN KEY (pastExecutionId) REFERENCES execution_entity (id) ON UPDATE NO ACTION ON DELETE SET NULL MATCH NONE" "test_case_execution" }o--o| "execution_entity" : "FOREIGN KEY (executionId) REFERENCES execution_entity (id) ON UPDATE NO ACTION ON DELETE SET NULL MATCH NONE" @@ -665,6 +682,12 @@ erDiagram varchar planId PK INTEGER revision PK } +"agent_skill_dependency" { + varchar_36_ agentId PK + datetime_3_ createdAt + varchar_36_ skillId PK + varchar skillVersionId FK +} "agent_task_definition" { varchar_36_ agentId FK datetime_3_ createdAt @@ -700,6 +723,12 @@ erDiagram varchar_128_ threadId PK datetime_3_ updatedAt } +"agent_version_skill_dependency" { + varchar_36_ agentVersionId PK + datetime_3_ createdAt + varchar_36_ skillId PK + varchar skillVersionId FK +} "agent_workflow_dependency" { varchar_36_ agentId PK datetime_3_ createdAt @@ -1637,6 +1666,35 @@ erDiagram datetime_3_ updatedAt varchar_36_ workflowId PK } +"skill" { + varchar_36_ agentId FK + datetime_3_ createdAt + varchar createdById FK + varchar_36_ id PK + varchar_36_ projectId FK + varchar_16_ source + datetime_3_ updatedAt +} +"skill_file" { + TEXT content + datetime_3_ createdAt + varchar_512_ path PK + varchar skillVersionId PK + datetime_3_ updatedAt +} +"skill_version" { + varchar_64_ contentHash + datetime_3_ createdAt + varchar createdById FK + varchar_1024_ description + TEXT frontmatter + varchar id PK + TEXT instructions + varchar_128_ name + varchar_36_ skillId FK + datetime_3_ updatedAt + INTEGER version +} "tag_entity" { datetime_3_ createdAt varchar_36_ id PK diff --git a/docs/generated/sqlite-schema/agent_history.md b/docs/generated/sqlite-schema/agent_history.md index af7c4ea1e48..b157fab3042 100644 --- a/docs/generated/sqlite-schema/agent_history.md +++ b/docs/generated/sqlite-schema/agent_history.md @@ -23,7 +23,7 @@ CREATE TABLE "agent_history" ("versionId" varchar(36) PRIMARY KEY NOT NULL, "age | skills | TEXT | | true | | | | | tools | TEXT | | true | | | | | updatedAt | datetime(3) | STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') | false | | | | -| versionId | varchar(36) | | false | [agent_execution_threads](agent_execution_threads.md) [agent_task_snapshot](agent_task_snapshot.md) [agents](agents.md) | | | +| versionId | varchar(36) | | false | [agent_execution_threads](agent_execution_threads.md) [agent_task_snapshot](agent_task_snapshot.md) [agent_version_skill_dependency](agent_version_skill_dependency.md) [agents](agents.md) | | | ## Constraints @@ -50,6 +50,7 @@ erDiagram "agent_history" }o--o| "user" : "FOREIGN KEY (publishedById) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE SET NULL MATCH NONE" "agent_execution_threads" }o--o| "agent_history" : "FOREIGN KEY (taskVersionId) REFERENCES agent_history (versionId) ON UPDATE NO ACTION ON DELETE SET NULL MATCH NONE" "agent_task_snapshot" |o--|| "agent_history" : "FOREIGN KEY (versionId) REFERENCES agent_history (versionId) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"agent_version_skill_dependency" |o--|| "agent_history" : "FOREIGN KEY (agentVersionId) REFERENCES agent_history (versionId) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "agents" }o--o| "agent_history" : "FOREIGN KEY (activeVersionId) REFERENCES agent_history (versionId) ON UPDATE NO ACTION ON DELETE SET NULL MATCH NONE" "agent_history" { @@ -128,6 +129,12 @@ erDiagram datetime_3_ updatedAt varchar_36_ versionId PK } +"agent_version_skill_dependency" { + varchar_36_ agentVersionId PK + datetime_3_ createdAt + varchar_36_ skillId PK + varchar skillVersionId FK +} ``` --- diff --git a/docs/generated/sqlite-schema/agent_skill_dependency.md b/docs/generated/sqlite-schema/agent_skill_dependency.md new file mode 100644 index 00000000000..114d3a3998e --- /dev/null +++ b/docs/generated/sqlite-schema/agent_skill_dependency.md @@ -0,0 +1,98 @@ +# agent_skill_dependency + +## Description + +
+Table Definition + +```sql +CREATE TABLE "agent_skill_dependency" ("agentId" varchar(36) NOT NULL, "skillId" varchar(36) NOT NULL, "skillVersionId" varchar, "createdAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), CONSTRAINT "FK_72325bb13511a51847c53fcb377" FOREIGN KEY ("agentId") REFERENCES "agents" ("id") ON DELETE CASCADE, CONSTRAINT "FK_068f21aefba31ae621482f396dc" FOREIGN KEY ("skillId") REFERENCES "skill" ("id") ON DELETE CASCADE, CONSTRAINT "FK_7676571bd6f41d9e32f0d066fe9" FOREIGN KEY ("skillVersionId") REFERENCES "skill_version" ("id") ON DELETE NO ACTION, PRIMARY KEY ("agentId", "skillId")) +``` + +
+ +## Columns + +| Name | Type | Default | Nullable | Children | Parents | Comment | +| ---- | ---- | ------- | -------- | -------- | ------- | ------- | +| agentId | varchar(36) | | false | | [agents](agents.md) | | +| createdAt | datetime(3) | STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') | false | | | | +| skillId | varchar(36) | | false | | [skill](skill.md) | | +| skillVersionId | varchar | | true | | [skill_version](skill_version.md) | | + +## Constraints + +| Name | Type | Definition | +| ---- | ---- | ---------- | +| - (Foreign key ID: 0) | FOREIGN KEY | FOREIGN KEY (skillVersionId) REFERENCES skill_version (id) ON UPDATE NO ACTION ON DELETE NO ACTION MATCH NONE | +| - (Foreign key ID: 1) | FOREIGN KEY | FOREIGN KEY (skillId) REFERENCES skill (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE | +| - (Foreign key ID: 2) | FOREIGN KEY | FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE | +| agentId | PRIMARY KEY | PRIMARY KEY (agentId) | +| skillId | PRIMARY KEY | PRIMARY KEY (skillId) | +| sqlite_autoindex_agent_skill_dependency_1 | PRIMARY KEY | PRIMARY KEY (agentId, skillId) | + +## Indexes + +| Name | Definition | +| ---- | ---------- | +| IDX_068f21aefba31ae621482f396d | CREATE INDEX "IDX_068f21aefba31ae621482f396d" ON "agent_skill_dependency" ("skillId") | +| sqlite_autoindex_agent_skill_dependency_1 | PRIMARY KEY (agentId, skillId) | + +## Relations + +```mermaid +erDiagram + +"agent_skill_dependency" |o--|| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"agent_skill_dependency" |o--|| "skill" : "FOREIGN KEY (skillId) REFERENCES skill (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"agent_skill_dependency" }o--o| "skill_version" : "FOREIGN KEY (skillVersionId) REFERENCES skill_version (id) ON UPDATE NO ACTION ON DELETE NO ACTION MATCH NONE" + +"agent_skill_dependency" { + varchar_36_ agentId PK + datetime_3_ createdAt + varchar_36_ skillId PK + varchar skillVersionId FK +} +"agents" { + varchar_36_ activeVersionId FK + boolean availableInMCP + datetime_3_ createdAt + varchar_36_ id PK + TEXT integrations + varchar_128_ name + varchar_255_ projectId FK + INTEGER revision + TEXT schema + datetime_3_ setupCompletedAt + TEXT skills + TEXT tools + datetime_3_ updatedAt + varchar_36_ versionId +} +"skill" { + varchar_36_ agentId FK + datetime_3_ createdAt + varchar createdById FK + varchar_36_ id PK + varchar_36_ projectId FK + varchar_16_ source + datetime_3_ updatedAt +} +"skill_version" { + varchar_64_ contentHash + datetime_3_ createdAt + varchar createdById FK + varchar_1024_ description + TEXT frontmatter + varchar id PK + TEXT instructions + varchar_128_ name + varchar_36_ skillId FK + datetime_3_ updatedAt + INTEGER version +} +``` + +--- + +> Generated by [tbls](https://github.com/k1LoW/tbls) diff --git a/docs/generated/sqlite-schema/agent_version_skill_dependency.md b/docs/generated/sqlite-schema/agent_version_skill_dependency.md new file mode 100644 index 00000000000..9d8971a4724 --- /dev/null +++ b/docs/generated/sqlite-schema/agent_version_skill_dependency.md @@ -0,0 +1,94 @@ +# agent_version_skill_dependency + +## Description + +
+Table Definition + +```sql +CREATE TABLE "agent_version_skill_dependency" ("agentVersionId" varchar(36) NOT NULL, "skillId" varchar(36) NOT NULL, "skillVersionId" varchar NOT NULL, "createdAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), CONSTRAINT "FK_97472baf9196d914d9cd9de6201" FOREIGN KEY ("agentVersionId") REFERENCES "agent_history" ("versionId") ON DELETE CASCADE, CONSTRAINT "FK_c494292243a7e510acd0331c3d1" FOREIGN KEY ("skillId") REFERENCES "skill" ("id") ON DELETE CASCADE, CONSTRAINT "FK_df63badfd7d3f2aa622ece471c4" FOREIGN KEY ("skillVersionId") REFERENCES "skill_version" ("id") ON DELETE NO ACTION, PRIMARY KEY ("agentVersionId", "skillId")) +``` + +
+ +## Columns + +| Name | Type | Default | Nullable | Children | Parents | Comment | +| ---- | ---- | ------- | -------- | -------- | ------- | ------- | +| agentVersionId | varchar(36) | | false | | [agent_history](agent_history.md) | | +| createdAt | datetime(3) | STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') | false | | | | +| skillId | varchar(36) | | false | | [skill](skill.md) | | +| skillVersionId | varchar | | false | | [skill_version](skill_version.md) | | + +## Constraints + +| Name | Type | Definition | +| ---- | ---- | ---------- | +| - (Foreign key ID: 0) | FOREIGN KEY | FOREIGN KEY (skillVersionId) REFERENCES skill_version (id) ON UPDATE NO ACTION ON DELETE NO ACTION MATCH NONE | +| - (Foreign key ID: 1) | FOREIGN KEY | FOREIGN KEY (skillId) REFERENCES skill (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE | +| - (Foreign key ID: 2) | FOREIGN KEY | FOREIGN KEY (agentVersionId) REFERENCES agent_history (versionId) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE | +| agentVersionId | PRIMARY KEY | PRIMARY KEY (agentVersionId) | +| skillId | PRIMARY KEY | PRIMARY KEY (skillId) | +| sqlite_autoindex_agent_version_skill_dependency_1 | PRIMARY KEY | PRIMARY KEY (agentVersionId, skillId) | + +## Indexes + +| Name | Definition | +| ---- | ---------- | +| IDX_c494292243a7e510acd0331c3d | CREATE INDEX "IDX_c494292243a7e510acd0331c3d" ON "agent_version_skill_dependency" ("skillId") | +| IDX_df63badfd7d3f2aa622ece471c | CREATE INDEX "IDX_df63badfd7d3f2aa622ece471c" ON "agent_version_skill_dependency" ("skillVersionId") | +| sqlite_autoindex_agent_version_skill_dependency_1 | PRIMARY KEY (agentVersionId, skillId) | + +## Relations + +```mermaid +erDiagram + +"agent_version_skill_dependency" |o--|| "agent_history" : "FOREIGN KEY (agentVersionId) REFERENCES agent_history (versionId) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"agent_version_skill_dependency" |o--|| "skill" : "FOREIGN KEY (skillId) REFERENCES skill (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"agent_version_skill_dependency" }o--|| "skill_version" : "FOREIGN KEY (skillVersionId) REFERENCES skill_version (id) ON UPDATE NO ACTION ON DELETE NO ACTION MATCH NONE" + +"agent_version_skill_dependency" { + varchar_36_ agentVersionId PK + datetime_3_ createdAt + varchar_36_ skillId PK + varchar skillVersionId FK +} +"agent_history" { + varchar_36_ agentId FK + varchar_255_ author + datetime_3_ createdAt + varchar publishedById FK + TEXT schema + TEXT skills + TEXT tools + datetime_3_ updatedAt + varchar_36_ versionId PK +} +"skill" { + varchar_36_ agentId FK + datetime_3_ createdAt + varchar createdById FK + varchar_36_ id PK + varchar_36_ projectId FK + varchar_16_ source + datetime_3_ updatedAt +} +"skill_version" { + varchar_64_ contentHash + datetime_3_ createdAt + varchar createdById FK + varchar_1024_ description + TEXT frontmatter + varchar id PK + TEXT instructions + varchar_128_ name + varchar_36_ skillId FK + datetime_3_ updatedAt + INTEGER version +} +``` + +--- + +> Generated by [tbls](https://github.com/k1LoW/tbls) diff --git a/docs/generated/sqlite-schema/agents.md b/docs/generated/sqlite-schema/agents.md index 1b0d460634d..b7feda944a9 100644 --- a/docs/generated/sqlite-schema/agents.md +++ b/docs/generated/sqlite-schema/agents.md @@ -18,7 +18,7 @@ CREATE TABLE "agents" ("id" varchar(36) PRIMARY KEY NOT NULL, "name" varchar(128 | activeVersionId | varchar(36) | | true | | [agent_history](agent_history.md) | | | availableInMCP | boolean | false | false | | | | | createdAt | datetime(3) | STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') | false | | | | -| id | varchar(36) | | false | [agent_background_job](agent_background_job.md) [agent_channel_status](agent_channel_status.md) [agent_chat_attachments](agent_chat_attachments.md) [agent_chat_subscriptions](agent_chat_subscriptions.md) [agent_checkpoints](agent_checkpoints.md) [agent_credential_dependency](agent_credential_dependency.md) [agent_eval_dataset](agent_eval_dataset.md) [agent_execution_threads](agent_execution_threads.md) [agent_files](agent_files.md) [agent_history](agent_history.md) [agent_task_definition](agent_task_definition.md) [agent_task_run_lock](agent_task_run_lock.md) [agent_workflow_dependency](agent_workflow_dependency.md) [agents_memory_entries](agents_memory_entries.md) [agents_memory_entry_candidates](agents_memory_entry_candidates.md) [agents_memory_entry_locks](agents_memory_entry_locks.md) [agents_memory_entry_sources](agents_memory_entry_sources.md) [agents_observation_cursors](agents_observation_cursors.md) [agents_observation_locks](agents_observation_locks.md) [agents_observations](agents_observations.md) | | | +| id | varchar(36) | | false | [agent_background_job](agent_background_job.md) [agent_channel_status](agent_channel_status.md) [agent_chat_attachments](agent_chat_attachments.md) [agent_chat_subscriptions](agent_chat_subscriptions.md) [agent_checkpoints](agent_checkpoints.md) [agent_credential_dependency](agent_credential_dependency.md) [agent_eval_dataset](agent_eval_dataset.md) [agent_execution_threads](agent_execution_threads.md) [agent_files](agent_files.md) [agent_history](agent_history.md) [agent_skill_dependency](agent_skill_dependency.md) [agent_task_definition](agent_task_definition.md) [agent_task_run_lock](agent_task_run_lock.md) [agent_workflow_dependency](agent_workflow_dependency.md) [agents_memory_entries](agents_memory_entries.md) [agents_memory_entry_candidates](agents_memory_entry_candidates.md) [agents_memory_entry_locks](agents_memory_entry_locks.md) [agents_memory_entry_sources](agents_memory_entry_sources.md) [agents_observation_cursors](agents_observation_cursors.md) [agents_observation_locks](agents_observation_locks.md) [agents_observations](agents_observations.md) [skill](skill.md) | | | | integrations | TEXT | '[]' | false | | | | | name | varchar(128) | | false | | | | | projectId | varchar(255) | | false | | [project](project.md) | | @@ -63,6 +63,7 @@ erDiagram "agent_execution_threads" }o--|| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "agent_files" }o--|| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "agent_history" }o--|| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"agent_skill_dependency" |o--|| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "agent_task_definition" }o--|| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "agent_task_run_lock" |o--|| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "agent_workflow_dependency" |o--|| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" @@ -73,6 +74,7 @@ erDiagram "agents_observation_cursors" |o--|| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "agents_observation_locks" |o--|| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "agents_observations" }o--|| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"skill" }o--o| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "agents" }o--|| "project" : "FOREIGN KEY (projectId) REFERENCES project (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "agents" { @@ -218,6 +220,12 @@ erDiagram varchar_2_ storedAt datetime_3_ updatedAt } +"agent_skill_dependency" { + varchar_36_ agentId PK + datetime_3_ createdAt + varchar_36_ skillId PK + varchar skillVersionId FK +} "agent_task_definition" { varchar_36_ agentId FK datetime_3_ createdAt @@ -322,6 +330,15 @@ erDiagram INTEGER tokenCount datetime_3_ updatedAt } +"skill" { + varchar_36_ agentId FK + datetime_3_ createdAt + varchar createdById FK + varchar_36_ id PK + varchar_36_ projectId FK + varchar_16_ source + datetime_3_ updatedAt +} "project" { datetime_3_ createdAt varchar creatorId FK diff --git a/docs/generated/sqlite-schema/project.md b/docs/generated/sqlite-schema/project.md index 62d8edb9bd9..46f39c7fb0b 100644 --- a/docs/generated/sqlite-schema/project.md +++ b/docs/generated/sqlite-schema/project.md @@ -20,7 +20,7 @@ CREATE TABLE "project" ("id" varchar(36) PRIMARY KEY NOT NULL, "name" varchar(25 | customTelemetryTags | TEXT | '[]' | false | | | | | description | varchar(512) | | true | | | | | icon | TEXT | | true | | | | -| id | varchar(36) | | false | [activity_event](activity_event.md) [agent_chat_attachments](agent_chat_attachments.md) [agent_execution_threads](agent_execution_threads.md) [agents](agents.md) [ai_preference](ai_preference.md) [data_table](data_table.md) [folder](folder.md) [insights_metadata](insights_metadata.md) [instance_ai_threads](instance_ai_threads.md) [project_pool_settings](project_pool_settings.md) [project_relation](project_relation.md) [project_secrets_provider_access](project_secrets_provider_access.md) [promotion_connection_project](promotion_connection_project.md) [role_mapping_rule_project](role_mapping_rule_project.md) [self_healing_result](self_healing_result.md) [shared_credentials](shared_credentials.md) [shared_workflow](shared_workflow.md) [type_availability_policy_scope](type_availability_policy_scope.md) [variables](variables.md) [workflow_review_request](workflow_review_request.md) [workflow_suggestion](workflow_suggestion.md) | | | +| id | varchar(36) | | false | [activity_event](activity_event.md) [agent_chat_attachments](agent_chat_attachments.md) [agent_execution_threads](agent_execution_threads.md) [agents](agents.md) [ai_preference](ai_preference.md) [data_table](data_table.md) [folder](folder.md) [insights_metadata](insights_metadata.md) [instance_ai_threads](instance_ai_threads.md) [project_pool_settings](project_pool_settings.md) [project_relation](project_relation.md) [project_secrets_provider_access](project_secrets_provider_access.md) [promotion_connection_project](promotion_connection_project.md) [role_mapping_rule_project](role_mapping_rule_project.md) [self_healing_result](self_healing_result.md) [shared_credentials](shared_credentials.md) [shared_workflow](shared_workflow.md) [skill](skill.md) [type_availability_policy_scope](type_availability_policy_scope.md) [variables](variables.md) [workflow_review_request](workflow_review_request.md) [workflow_suggestion](workflow_suggestion.md) | | | | name | varchar(255) | | false | | | | | type | varchar(36) | | false | | | | | updatedAt | datetime(3) | STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') | false | | | | @@ -62,6 +62,7 @@ erDiagram "self_healing_result" }o--|| "project" : "FOREIGN KEY (projectId) REFERENCES project (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "shared_credentials" |o--|| "project" : "FOREIGN KEY (projectId) REFERENCES project (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "shared_workflow" |o--|| "project" : "FOREIGN KEY (projectId) REFERENCES project (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"skill" }o--o| "project" : "FOREIGN KEY (projectId) REFERENCES project (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "type_availability_policy_scope" }o--o| "project" : "FOREIGN KEY (projectId) REFERENCES project (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "variables" }o--o| "project" : "FOREIGN KEY (projectId) REFERENCES project (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "workflow_review_request" }o--|| "project" : "FOREIGN KEY (projectId) REFERENCES project (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" @@ -261,6 +262,15 @@ erDiagram datetime_3_ updatedAt varchar_36_ workflowId PK } +"skill" { + varchar_36_ agentId FK + datetime_3_ createdAt + varchar createdById FK + varchar_36_ id PK + varchar_36_ projectId FK + varchar_16_ source + datetime_3_ updatedAt +} "type_availability_policy_scope" { datetime_3_ createdAt varchar_16_ defaultAction diff --git a/docs/generated/sqlite-schema/skill.md b/docs/generated/sqlite-schema/skill.md new file mode 100644 index 00000000000..8be4273cb95 --- /dev/null +++ b/docs/generated/sqlite-schema/skill.md @@ -0,0 +1,139 @@ +# skill + +## Description + +
+Table Definition + +```sql +CREATE TABLE "skill" ("id" varchar(36) PRIMARY KEY NOT NULL, "projectId" varchar(36), "agentId" varchar(36), "source" varchar(16) NOT NULL, "createdById" varchar, "createdAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "updatedAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), CONSTRAINT "CHK_skill_single_target" CHECK ("agentId" IS NULL OR "projectId" IS NULL), CONSTRAINT "FK_402ed37bff0d3134f6e782455ed" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE, CONSTRAINT "FK_7d4fb6af107e507d9a86293cf9d" FOREIGN KEY ("agentId") REFERENCES "agents" ("id") ON DELETE CASCADE, CONSTRAINT "FK_4de4501583cd1fcd6f5ea85f547" FOREIGN KEY ("createdById") REFERENCES "user" ("id") ON DELETE SET NULL) +``` + +
+ +## Columns + +| Name | Type | Default | Nullable | Children | Parents | Comment | +| ---- | ---- | ------- | -------- | -------- | ------- | ------- | +| agentId | varchar(36) | | true | | [agents](agents.md) | | +| createdAt | datetime(3) | STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') | false | | | | +| createdById | varchar | | true | | [user](user.md) | | +| id | varchar(36) | | false | [agent_skill_dependency](agent_skill_dependency.md) [agent_version_skill_dependency](agent_version_skill_dependency.md) [skill_version](skill_version.md) | | | +| projectId | varchar(36) | | true | | [project](project.md) | | +| source | varchar(16) | | false | | | | +| updatedAt | datetime(3) | STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') | false | | | | + +## Constraints + +| Name | Type | Definition | +| ---- | ---- | ---------- | +| - | CHECK | CHECK ("agentId" IS NULL OR "projectId" IS NULL) | +| - (Foreign key ID: 0) | FOREIGN KEY | FOREIGN KEY (createdById) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE SET NULL MATCH NONE | +| - (Foreign key ID: 1) | FOREIGN KEY | FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE | +| - (Foreign key ID: 2) | FOREIGN KEY | FOREIGN KEY (projectId) REFERENCES project (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE | +| id | PRIMARY KEY | PRIMARY KEY (id) | +| sqlite_autoindex_skill_1 | PRIMARY KEY | PRIMARY KEY (id) | + +## Indexes + +| Name | Definition | +| ---- | ---------- | +| IDX_402ed37bff0d3134f6e782455e | CREATE INDEX "IDX_402ed37bff0d3134f6e782455e" ON "skill" ("projectId") | +| IDX_7d4fb6af107e507d9a86293cf9 | CREATE INDEX "IDX_7d4fb6af107e507d9a86293cf9" ON "skill" ("agentId") | +| sqlite_autoindex_skill_1 | PRIMARY KEY (id) | + +## Relations + +```mermaid +erDiagram + +"skill" }o--o| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"skill" }o--o| "user" : "FOREIGN KEY (createdById) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE SET NULL MATCH NONE" +"agent_skill_dependency" |o--|| "skill" : "FOREIGN KEY (skillId) REFERENCES skill (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"agent_version_skill_dependency" |o--|| "skill" : "FOREIGN KEY (skillId) REFERENCES skill (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"skill_version" }o--|| "skill" : "FOREIGN KEY (skillId) REFERENCES skill (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"skill" }o--o| "project" : "FOREIGN KEY (projectId) REFERENCES project (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" + +"skill" { + varchar_36_ agentId FK + datetime_3_ createdAt + varchar createdById FK + varchar_36_ id PK + varchar_36_ projectId FK + varchar_16_ source + datetime_3_ updatedAt +} +"agents" { + varchar_36_ activeVersionId FK + boolean availableInMCP + datetime_3_ createdAt + varchar_36_ id PK + TEXT integrations + varchar_128_ name + varchar_255_ projectId FK + INTEGER revision + TEXT schema + datetime_3_ setupCompletedAt + TEXT skills + TEXT tools + datetime_3_ updatedAt + varchar_36_ versionId +} +"user" { + datetime_3_ createdAt + boolean disabled + varchar_255_ email + varchar_32_ firstName + varchar id PK + date lastActiveAt + varchar_32_ lastName + boolean mfaEnabled + TEXT mfaRecoveryCodes + TEXT mfaSecret + varchar password + TEXT personalizationAnswers + varchar_128_ roleSlug FK + TEXT settings + datetime_3_ updatedAt +} +"agent_skill_dependency" { + varchar_36_ agentId PK + datetime_3_ createdAt + varchar_36_ skillId PK + varchar skillVersionId FK +} +"agent_version_skill_dependency" { + varchar_36_ agentVersionId PK + datetime_3_ createdAt + varchar_36_ skillId PK + varchar skillVersionId FK +} +"skill_version" { + varchar_64_ contentHash + datetime_3_ createdAt + varchar createdById FK + varchar_1024_ description + TEXT frontmatter + varchar id PK + TEXT instructions + varchar_128_ name + varchar_36_ skillId FK + datetime_3_ updatedAt + INTEGER version +} +"project" { + datetime_3_ createdAt + varchar creatorId FK + TEXT customTelemetryTags + varchar_512_ description + TEXT icon + varchar_36_ id PK + varchar_255_ name + varchar_36_ type + datetime_3_ updatedAt +} +``` + +--- + +> Generated by [tbls](https://github.com/k1LoW/tbls) diff --git a/docs/generated/sqlite-schema/skill_file.md b/docs/generated/sqlite-schema/skill_file.md new file mode 100644 index 00000000000..549a0742c4b --- /dev/null +++ b/docs/generated/sqlite-schema/skill_file.md @@ -0,0 +1,70 @@ +# skill_file + +## Description + +
+Table Definition + +```sql +CREATE TABLE "skill_file" ("skillVersionId" varchar NOT NULL, "path" varchar(512) NOT NULL, "content" text NOT NULL, "createdAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "updatedAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), CONSTRAINT "FK_e9ab50b795ec8858702b7333d13" FOREIGN KEY ("skillVersionId") REFERENCES "skill_version" ("id") ON DELETE CASCADE, PRIMARY KEY ("skillVersionId", "path")) +``` + +
+ +## Columns + +| Name | Type | Default | Nullable | Children | Parents | Comment | +| ---- | ---- | ------- | -------- | -------- | ------- | ------- | +| content | TEXT | | false | | | | +| createdAt | datetime(3) | STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') | false | | | | +| path | varchar(512) | | false | | | | +| skillVersionId | varchar | | false | | [skill_version](skill_version.md) | | +| updatedAt | datetime(3) | STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') | false | | | | + +## Constraints + +| Name | Type | Definition | +| ---- | ---- | ---------- | +| - (Foreign key ID: 0) | FOREIGN KEY | FOREIGN KEY (skillVersionId) REFERENCES skill_version (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE | +| path | PRIMARY KEY | PRIMARY KEY (path) | +| skillVersionId | PRIMARY KEY | PRIMARY KEY (skillVersionId) | +| sqlite_autoindex_skill_file_1 | PRIMARY KEY | PRIMARY KEY (skillVersionId, path) | + +## Indexes + +| Name | Definition | +| ---- | ---------- | +| sqlite_autoindex_skill_file_1 | PRIMARY KEY (skillVersionId, path) | + +## Relations + +```mermaid +erDiagram + +"skill_file" |o--|| "skill_version" : "FOREIGN KEY (skillVersionId) REFERENCES skill_version (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" + +"skill_file" { + TEXT content + datetime_3_ createdAt + varchar_512_ path PK + varchar skillVersionId PK + datetime_3_ updatedAt +} +"skill_version" { + varchar_64_ contentHash + datetime_3_ createdAt + varchar createdById FK + varchar_1024_ description + TEXT frontmatter + varchar id PK + TEXT instructions + varchar_128_ name + varchar_36_ skillId FK + datetime_3_ updatedAt + INTEGER version +} +``` + +--- + +> Generated by [tbls](https://github.com/k1LoW/tbls) diff --git a/docs/generated/sqlite-schema/skill_version.md b/docs/generated/sqlite-schema/skill_version.md new file mode 100644 index 00000000000..23a5e245be9 --- /dev/null +++ b/docs/generated/sqlite-schema/skill_version.md @@ -0,0 +1,121 @@ +# skill_version + +## Description + +
+Table Definition + +```sql +CREATE TABLE "skill_version" ("id" varchar PRIMARY KEY NOT NULL, "skillId" varchar(36) NOT NULL, "version" integer NOT NULL, "name" varchar(128) NOT NULL, "description" varchar(1024) NOT NULL, "instructions" text NOT NULL, "frontmatter" text, "contentHash" varchar(64) NOT NULL, "createdById" varchar, "createdAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "updatedAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), CONSTRAINT "UQ_93bb78a1eb4e0890fac6b69df95" UNIQUE ("skillId", "version"), CONSTRAINT "CHK_skill_version_version" CHECK ("version" > 0), CONSTRAINT "FK_f87064c0a29efd2d5195328d91a" FOREIGN KEY ("skillId") REFERENCES "skill" ("id") ON DELETE CASCADE, CONSTRAINT "FK_9565d0fbf32cd463f9b47c7adab" FOREIGN KEY ("createdById") REFERENCES "user" ("id") ON DELETE SET NULL) +``` + +
+ +## Columns + +| Name | Type | Default | Nullable | Children | Parents | Comment | +| ---- | ---- | ------- | -------- | -------- | ------- | ------- | +| contentHash | varchar(64) | | false | | | | +| createdAt | datetime(3) | STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') | false | | | | +| createdById | varchar | | true | | [user](user.md) | | +| description | varchar(1024) | | false | | | | +| frontmatter | TEXT | | true | | | | +| id | varchar | | false | [agent_skill_dependency](agent_skill_dependency.md) [agent_version_skill_dependency](agent_version_skill_dependency.md) [skill_file](skill_file.md) | | | +| instructions | TEXT | | false | | | | +| name | varchar(128) | | false | | | | +| skillId | varchar(36) | | false | | [skill](skill.md) | | +| updatedAt | datetime(3) | STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') | false | | | | +| version | INTEGER | | false | | | | + +## Constraints + +| Name | Type | Definition | +| ---- | ---- | ---------- | +| - | CHECK | CHECK ("version" > 0) | +| - (Foreign key ID: 0) | FOREIGN KEY | FOREIGN KEY (createdById) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE SET NULL MATCH NONE | +| - (Foreign key ID: 1) | FOREIGN KEY | FOREIGN KEY (skillId) REFERENCES skill (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE | +| id | PRIMARY KEY | PRIMARY KEY (id) | +| sqlite_autoindex_skill_version_1 | PRIMARY KEY | PRIMARY KEY (id) | +| sqlite_autoindex_skill_version_2 | UNIQUE | UNIQUE (skillId, version) | + +## Indexes + +| Name | Definition | +| ---- | ---------- | +| sqlite_autoindex_skill_version_1 | PRIMARY KEY (id) | +| sqlite_autoindex_skill_version_2 | UNIQUE (skillId, version) | + +## Relations + +```mermaid +erDiagram + +"skill_version" }o--o| "user" : "FOREIGN KEY (createdById) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE SET NULL MATCH NONE" +"agent_skill_dependency" }o--o| "skill_version" : "FOREIGN KEY (skillVersionId) REFERENCES skill_version (id) ON UPDATE NO ACTION ON DELETE NO ACTION MATCH NONE" +"agent_version_skill_dependency" }o--|| "skill_version" : "FOREIGN KEY (skillVersionId) REFERENCES skill_version (id) ON UPDATE NO ACTION ON DELETE NO ACTION MATCH NONE" +"skill_file" |o--|| "skill_version" : "FOREIGN KEY (skillVersionId) REFERENCES skill_version (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"skill_version" }o--|| "skill" : "FOREIGN KEY (skillId) REFERENCES skill (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" + +"skill_version" { + varchar_64_ contentHash + datetime_3_ createdAt + varchar createdById FK + varchar_1024_ description + TEXT frontmatter + varchar id PK + TEXT instructions + varchar_128_ name + varchar_36_ skillId FK + datetime_3_ updatedAt + INTEGER version +} +"user" { + datetime_3_ createdAt + boolean disabled + varchar_255_ email + varchar_32_ firstName + varchar id PK + date lastActiveAt + varchar_32_ lastName + boolean mfaEnabled + TEXT mfaRecoveryCodes + TEXT mfaSecret + varchar password + TEXT personalizationAnswers + varchar_128_ roleSlug FK + TEXT settings + datetime_3_ updatedAt +} +"agent_skill_dependency" { + varchar_36_ agentId PK + datetime_3_ createdAt + varchar_36_ skillId PK + varchar skillVersionId FK +} +"agent_version_skill_dependency" { + varchar_36_ agentVersionId PK + datetime_3_ createdAt + varchar_36_ skillId PK + varchar skillVersionId FK +} +"skill_file" { + TEXT content + datetime_3_ createdAt + varchar_512_ path PK + varchar skillVersionId PK + datetime_3_ updatedAt +} +"skill" { + varchar_36_ agentId FK + datetime_3_ createdAt + varchar createdById FK + varchar_36_ id PK + varchar_36_ projectId FK + varchar_16_ source + datetime_3_ updatedAt +} +``` + +--- + +> Generated by [tbls](https://github.com/k1LoW/tbls) diff --git a/docs/generated/sqlite-schema/user.md b/docs/generated/sqlite-schema/user.md index bea5531dfa9..1402b80f8f9 100644 --- a/docs/generated/sqlite-schema/user.md +++ b/docs/generated/sqlite-schema/user.md @@ -19,7 +19,7 @@ CREATE TABLE "user" ("id" varchar PRIMARY KEY, "email" varchar(255), "firstName" | disabled | boolean | FALSE | false | | | | | email | varchar(255) | | true | | | | | firstName | varchar(32) | | true | | | | -| id | varchar | | true | [activity_event](activity_event.md) [agent_eval_dataset](agent_eval_dataset.md) [agent_eval_rating](agent_eval_rating.md) [agent_eval_run](agent_eval_run.md) [agent_execution_threads](agent_execution_threads.md) [agent_history](agent_history.md) [ai_preference](ai_preference.md) [auth_identity](auth_identity.md) [chat_hub_agents](chat_hub_agents.md) [chat_hub_sessions](chat_hub_sessions.md) [chat_hub_tools](chat_hub_tools.md) [dynamic_credential_user_entry](dynamic_credential_user_entry.md) [evaluation_collection](evaluation_collection.md) [idempotency_key](idempotency_key.md) [instance_ai_mcp_registry_connections](instance_ai_mcp_registry_connections.md) [instance_ai_pending_confirmations](instance_ai_pending_confirmations.md) [instance_ai_thread_grants](instance_ai_thread_grants.md) [instance_ai_thread_tabs](instance_ai_thread_tabs.md) [migration_workflow_owner](migration_workflow_owner.md) [oauth_access_tokens](oauth_access_tokens.md) [oauth_authorization_codes](oauth_authorization_codes.md) [oauth_refresh_tokens](oauth_refresh_tokens.md) [oauth_user_consents](oauth_user_consents.md) [project](project.md) [project_relation](project_relation.md) [self_healing_result](self_healing_result.md) [trusted_source_identity](trusted_source_identity.md) [user_api_keys](user_api_keys.md) [user_favorites](user_favorites.md) [workflow_builder_session](workflow_builder_session.md) [workflow_publish_history](workflow_publish_history.md) [workflow_review_activity](workflow_review_activity.md) [workflow_review_activity_comment](workflow_review_activity_comment.md) [workflow_review_request](workflow_review_request.md) [workflow_review_request_authors](workflow_review_request_authors.md) [workflow_review_request_reviewers](workflow_review_request_reviewers.md) [workflow_suggestion](workflow_suggestion.md) [workflow_suggestion_activity](workflow_suggestion_activity.md) | | | +| id | varchar | | true | [activity_event](activity_event.md) [agent_eval_dataset](agent_eval_dataset.md) [agent_eval_rating](agent_eval_rating.md) [agent_eval_run](agent_eval_run.md) [agent_execution_threads](agent_execution_threads.md) [agent_history](agent_history.md) [ai_preference](ai_preference.md) [auth_identity](auth_identity.md) [chat_hub_agents](chat_hub_agents.md) [chat_hub_sessions](chat_hub_sessions.md) [chat_hub_tools](chat_hub_tools.md) [dynamic_credential_user_entry](dynamic_credential_user_entry.md) [evaluation_collection](evaluation_collection.md) [idempotency_key](idempotency_key.md) [instance_ai_mcp_registry_connections](instance_ai_mcp_registry_connections.md) [instance_ai_pending_confirmations](instance_ai_pending_confirmations.md) [instance_ai_thread_grants](instance_ai_thread_grants.md) [instance_ai_thread_tabs](instance_ai_thread_tabs.md) [migration_workflow_owner](migration_workflow_owner.md) [oauth_access_tokens](oauth_access_tokens.md) [oauth_authorization_codes](oauth_authorization_codes.md) [oauth_refresh_tokens](oauth_refresh_tokens.md) [oauth_user_consents](oauth_user_consents.md) [project](project.md) [project_relation](project_relation.md) [self_healing_result](self_healing_result.md) [skill](skill.md) [skill_version](skill_version.md) [trusted_source_identity](trusted_source_identity.md) [user_api_keys](user_api_keys.md) [user_favorites](user_favorites.md) [workflow_builder_session](workflow_builder_session.md) [workflow_publish_history](workflow_publish_history.md) [workflow_review_activity](workflow_review_activity.md) [workflow_review_activity_comment](workflow_review_activity_comment.md) [workflow_review_request](workflow_review_request.md) [workflow_review_request_authors](workflow_review_request_authors.md) [workflow_review_request_reviewers](workflow_review_request_reviewers.md) [workflow_suggestion](workflow_suggestion.md) [workflow_suggestion_activity](workflow_suggestion_activity.md) | | | | lastActiveAt | date | | true | | | | | lastName | varchar(32) | | true | | | | | mfaEnabled | boolean | FALSE | false | | | | @@ -82,6 +82,8 @@ erDiagram "project_relation" |o--|| "user" : "FOREIGN KEY (userId) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "self_healing_result" }o--o| "user" : "FOREIGN KEY (dismissedById) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE SET NULL MATCH NONE" "self_healing_result" }o--|| "user" : "FOREIGN KEY (backgroundUserId) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" +"skill" }o--o| "user" : "FOREIGN KEY (createdById) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE SET NULL MATCH NONE" +"skill_version" }o--o| "user" : "FOREIGN KEY (createdById) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE SET NULL MATCH NONE" "trusted_source_identity" }o--|| "user" : "FOREIGN KEY (userId) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "user_api_keys" }o--|| "user" : "FOREIGN KEY (userId) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" "user_favorites" }o--|| "user" : "FOREIGN KEY (userId) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE" @@ -404,6 +406,28 @@ erDiagram TEXT usage varchar_36_ workflowId FK } +"skill" { + varchar_36_ agentId FK + datetime_3_ createdAt + varchar createdById FK + varchar_36_ id PK + varchar_36_ projectId FK + varchar_16_ source + datetime_3_ updatedAt +} +"skill_version" { + varchar_64_ contentHash + datetime_3_ createdAt + varchar createdById FK + varchar_1024_ description + TEXT frontmatter + varchar id PK + TEXT instructions + varchar_128_ name + varchar_36_ skillId FK + datetime_3_ updatedAt + INTEGER version +} "trusted_source_identity" { datetime_3_ createdAt datetime_3_ lastSeenAt diff --git a/packages/@n8n/db/src/migrations/common/1791818723687-CreateSkillsHubTables.ts b/packages/@n8n/db/src/migrations/common/1791818723687-CreateSkillsHubTables.ts new file mode 100644 index 00000000000..88b9a830ccc --- /dev/null +++ b/packages/@n8n/db/src/migrations/common/1791818723687-CreateSkillsHubTables.ts @@ -0,0 +1,197 @@ +import type { MigrationContext, ReversibleMigration } from '../migration-types'; + +const SKILL_TABLE = 'skill'; +const SKILL_VERSION_TABLE = 'skill_version'; +const SKILL_FILE_TABLE = 'skill_file'; +const AGENT_SKILL_DEPENDENCY_TABLE = 'agent_skill_dependency'; +const AGENT_VERSION_SKILL_DEPENDENCY_TABLE = 'agent_version_skill_dependency'; + +/** + * The skills hub: skills live outside the agent row, so many agents can use one skill. + * A skill belongs to one target: a project (team or personal, for its agents), one agent + * (only that agent can use it; its project is the agent's), or the instance (neither set). Its name and + * content live in numbered, immutable versions: a Save that changes the content creates + * the next one, agents read the latest, and agent publishes pin the one they ran. + */ +export class CreateSkillsHubTables1791818723687 implements ReversibleMigration { + async up(context: MigrationContext) { + await this.createSkillTable(context); + await this.createSkillVersionTable(context); + await this.createSkillFileTable(context); + await this.createAgentSkillDependencyTable(context); + await this.createAgentVersionSkillDependencyTable(context); + } + + async down({ schemaBuilder: { dropTable } }: MigrationContext) { + await dropTable(AGENT_VERSION_SKILL_DEPENDENCY_TABLE); + await dropTable(AGENT_SKILL_DEPENDENCY_TABLE); + await dropTable(SKILL_FILE_TABLE); + await dropTable(SKILL_VERSION_TABLE); + await dropTable(SKILL_TABLE); + } + + private async createSkillTable({ + schemaBuilder: { createTable, column }, + tablePrefix, + escape, + }: MigrationContext) { + // The id is the identity. Names live on skill_version and may repeat. + await createTable(SKILL_TABLE) + .withColumns( + column('id').varchar(36).primary.comment('skill_, the same format agents use'), + column('projectId') + .varchar(36) + .comment('Set for a project skill, team or personal. NULL otherwise'), + column('agentId') + .varchar(36) + .comment( + 'Set when only this agent can use the skill. projectId is then NULL: the agent holds the project', + ), + // No CHECK on the values: new sources (upload, Git sync, AI-written) must not + // recreate the table on SQLite. The service validates them. + column('source') + .varchar(16) + .notNull.comment( + 'How the skill was created, set by the server: "ui" (the skills hub) or "agent" (the agent builder or the copy of agent skills)', + ), + column('createdById').uuid.comment('Author. NULL after the author is deleted'), + ) + .withTimestamps.withIndexOn(['projectId']) + .withIndexOn(['agentId']) + .withForeignKey('projectId', { + tableName: 'project', + columnName: 'id', + onDelete: 'CASCADE', + }) + // An agent skill goes with its agent, as agent skills do today. + .withForeignKey('agentId', { + tableName: 'agents', + columnName: 'id', + onDelete: 'CASCADE', + }) + .withForeignKey('createdById', { + tableName: 'user', + columnName: 'id', + onDelete: 'SET NULL', + }) + // One target. An agent skill takes its project from the agent, so the two cannot + // disagree, and the skill follows the agent if the agent moves. + .withCheck( + `CHK_${tablePrefix}skill_single_target`, + `${escape.columnName('agentId')} IS NULL OR ${escape.columnName('projectId')} IS NULL`, + ); + } + + private async createSkillVersionTable({ + schemaBuilder: { createTable, column }, + tablePrefix, + escape, + }: MigrationContext) { + await createTable(SKILL_VERSION_TABLE) + .withColumns( + column('id').uuid.primary, + column('skillId').varchar(36).notNull, + column('version').int.notNull.comment( + '1..n per skill. A Save that changes the content adds one; none ever changes', + ), + column('name') + .varchar(128) + .notNull.comment('Free-text skill name, as it was when this version was saved'), + column('description').varchar(1024).notNull, + column('instructions').text.notNull, + column('frontmatter').json.comment( + 'SKILL.md frontmatter fields other than name and description, e.g. allowed-tools', + ), + column('contentHash') + .varchar(64) + .notNull.comment( + 'sha256 of name, description, instructions, frontmatter and files. Save creates no version when the content matches the latest one', + ), + column('createdById').uuid.comment('Author. NULL after the author is deleted'), + ) + .withTimestamps.withUniqueConstraintOn(['skillId', 'version']) + .withCheck(`CHK_${tablePrefix}skill_version_version`, `${escape.columnName('version')} > 0`) + .withForeignKey('skillId', { + tableName: SKILL_TABLE, + columnName: 'id', + onDelete: 'CASCADE', + }) + .withForeignKey('createdById', { + tableName: 'user', + columnName: 'id', + onDelete: 'SET NULL', + }); + } + + private async createSkillFileTable({ schemaBuilder: { createTable, column } }: MigrationContext) { + await createTable(SKILL_FILE_TABLE) + .withColumns( + column('skillVersionId').uuid.primary, + column('path').varchar(512).primary.comment('Relative path, references/*.md in v1'), + column('content').text.notNull, + ) + .withTimestamps.withForeignKey('skillVersionId', { + tableName: SKILL_VERSION_TABLE, + columnName: 'id', + onDelete: 'CASCADE', + }); + } + + private async createAgentSkillDependencyTable({ + schemaBuilder: { createTable, column }, + }: MigrationContext) { + await createTable(AGENT_SKILL_DEPENDENCY_TABLE) + .withColumns( + column('agentId').varchar(36).primary, + column('skillId').varchar(36).primary, + // An agent draft normally follows the skill's latest saved version. A revert + // pins the version it had; the pin clears when the skill is saved again. + column('skillVersionId').uuid.comment( + 'Set when the agent draft pins a saved version. NULL = follows the latest saved version', + ), + ) + .withCreatedAt.withIndexOn(['skillId']) + .withForeignKey('agentId', { tableName: 'agents', columnName: 'id', onDelete: 'CASCADE' }) + .withForeignKey('skillId', { tableName: SKILL_TABLE, columnName: 'id', onDelete: 'CASCADE' }) + // NO ACTION keeps a pinned version from being deleted on its own. A skill delete + // removes these rows first, through the skillId cascade. + .withForeignKey('skillVersionId', { + tableName: SKILL_VERSION_TABLE, + columnName: 'id', + onDelete: 'NO ACTION', + }); + } + + private async createAgentVersionSkillDependencyTable({ + schemaBuilder: { createTable, column }, + }: MigrationContext) { + await createTable(AGENT_VERSION_SKILL_DEPENDENCY_TABLE) + .withColumns( + column('agentVersionId').varchar(36).primary, + column('skillId').varchar(36).primary, + column('skillVersionId').uuid.notNull, + ) + .withCreatedAt.withIndexOn(['skillId']) + // This table grows with every publish, and "used by" reads it by version. + .withIndexOn(['skillVersionId']) + .withForeignKey('agentVersionId', { + tableName: 'agent_history', + columnName: 'versionId', + onDelete: 'CASCADE', + }) + // CASCADE, as in agent_skill_dependency: a user or project delete removes a skill + // and the agents that pin it, and Postgres checks NO ACTION before the agent + // cascade runs. The service refuses to delete a skill that is in use. + .withForeignKey('skillId', { + tableName: SKILL_TABLE, + columnName: 'id', + onDelete: 'CASCADE', + }) + // NO ACTION keeps a pinned version from being deleted on its own. + .withForeignKey('skillVersionId', { + tableName: SKILL_VERSION_TABLE, + columnName: 'id', + onDelete: 'NO ACTION', + }); + } +} diff --git a/packages/cli/src/modules/agents/agents.module.ts b/packages/cli/src/modules/agents/agents.module.ts index a0631c17c91..891c3d31f72 100644 --- a/packages/cli/src/modules/agents/agents.module.ts +++ b/packages/cli/src/modules/agents/agents.module.ts @@ -274,6 +274,13 @@ export class AgentsModule implements ModuleInterface { const { AgentMemoryEntrySourceEntity } = await import( './entities/agent-memory-entry-source.entity.js' ); + const { Skill } = await import('./entities/skill.entity.js'); + const { SkillVersion } = await import('./entities/skill-version.entity.js'); + const { SkillFile } = await import('./entities/skill-file.entity.js'); + const { AgentSkillDependency } = await import('./entities/agent-skill-dependency.entity.js'); + const { AgentVersionSkillDependency } = await import( + './entities/agent-version-skill-dependency.entity.js' + ); return [ Agent, @@ -308,6 +315,11 @@ export class AgentsModule implements ModuleInterface { AgentMemoryEntryCandidateEntity, AgentMemoryEntryLockEntity, AgentMemoryEntrySourceEntity, + Skill, + SkillVersion, + SkillFile, + AgentSkillDependency, + AgentVersionSkillDependency, ]; } diff --git a/packages/cli/src/modules/agents/entities/agent-skill-dependency.entity.ts b/packages/cli/src/modules/agents/entities/agent-skill-dependency.entity.ts new file mode 100644 index 00000000000..c96ae5149d3 --- /dev/null +++ b/packages/cli/src/modules/agents/entities/agent-skill-dependency.entity.ts @@ -0,0 +1,20 @@ +import { WithCreatedAt } from '@n8n/db'; +import { Column, Entity, Index, PrimaryColumn } from '@n8n/typeorm'; + +/** + * Mirrors the skill refs of an agent draft, disabled refs included. A row with a + * `skillVersionId` is pinned: that draft reads that saved version instead of the + * skill's latest saved version, so a new Save does not reach it. + */ +@Entity({ name: 'agent_skill_dependency' }) +export class AgentSkillDependency extends WithCreatedAt { + @PrimaryColumn({ type: 'varchar', length: 36 }) + agentId: string; + + @Index() + @PrimaryColumn({ type: 'varchar', length: 36 }) + skillId: string; + + @Column({ type: 'uuid', nullable: true }) + skillVersionId: string | null; +} diff --git a/packages/cli/src/modules/agents/entities/agent-version-skill-dependency.entity.ts b/packages/cli/src/modules/agents/entities/agent-version-skill-dependency.entity.ts new file mode 100644 index 00000000000..a85d4b2e5b4 --- /dev/null +++ b/packages/cli/src/modules/agents/entities/agent-version-skill-dependency.entity.ts @@ -0,0 +1,17 @@ +import { WithCreatedAt } from '@n8n/db'; +import { Column, Entity, Index, PrimaryColumn } from '@n8n/typeorm'; + +/** Pins one skill version to one published agent version. */ +@Entity({ name: 'agent_version_skill_dependency' }) +export class AgentVersionSkillDependency extends WithCreatedAt { + @PrimaryColumn({ type: 'varchar', length: 36 }) + agentVersionId: string; + + @Index() + @PrimaryColumn({ type: 'varchar', length: 36 }) + skillId: string; + + @Index() + @Column({ type: 'uuid' }) + skillVersionId: string; +} diff --git a/packages/cli/src/modules/agents/entities/skill-file.entity.ts b/packages/cli/src/modules/agents/entities/skill-file.entity.ts new file mode 100644 index 00000000000..e103e37f5b1 --- /dev/null +++ b/packages/cli/src/modules/agents/entities/skill-file.entity.ts @@ -0,0 +1,15 @@ +import { WithTimestamps } from '@n8n/db'; +import { Column, Entity, PrimaryColumn } from '@n8n/typeorm'; + +/** A file that belongs to one skill version. Only `references/*.md` in v1. */ +@Entity({ name: 'skill_file' }) +export class SkillFile extends WithTimestamps { + @PrimaryColumn({ type: 'uuid' }) + skillVersionId: string; + + @PrimaryColumn({ type: 'varchar', length: 512 }) + path: string; + + @Column({ type: 'text' }) + content: string; +} diff --git a/packages/cli/src/modules/agents/entities/skill-version.entity.ts b/packages/cli/src/modules/agents/entities/skill-version.entity.ts new file mode 100644 index 00000000000..01990da668f --- /dev/null +++ b/packages/cli/src/modules/agents/entities/skill-version.entity.ts @@ -0,0 +1,49 @@ +import { JsonColumn, WithTimestamps } from '@n8n/db'; +import { Check, Column, Entity, Index, PrimaryColumn } from '@n8n/typeorm'; + +/** + * SKILL.md frontmatter fields other than name and description, e.g. `allowed-tools`, + * stored as given. The standard allows objects and lists, so values are not narrowed. + */ +export type SkillFrontmatter = Record; + +/** + * One saved version of a skill. A Save that changes the content adds the next number; + * a version never changes. Agents read the latest one unless a revert pinned an older one. + */ +@Entity({ name: 'skill_version' }) +@Index(['skillId', 'version'], { unique: true }) +@Check('"version" > 0') +export class SkillVersion extends WithTimestamps { + @PrimaryColumn({ type: 'uuid' }) + id: string; + + @Column({ type: 'varchar', length: 36 }) + skillId: string; + + @Column({ type: 'int' }) + version: number; + + /** Free-text name, as it was when this version was saved. */ + @Column({ type: 'varchar', length: 128 }) + name: string; + + @Column({ type: 'varchar', length: 1024 }) + description: string; + + @Column({ type: 'text' }) + instructions: string; + + @JsonColumn({ nullable: true }) + frontmatter: SkillFrontmatter | null; + + /** + * sha256 of name, description, instructions, frontmatter and files (see + * `skillContentHash`). Save creates no version when the content matches the latest one. + */ + @Column({ type: 'varchar', length: 64 }) + contentHash: string; + + @Column({ type: 'uuid', nullable: true }) + createdById: string | null; +} diff --git a/packages/cli/src/modules/agents/entities/skill.entity.ts b/packages/cli/src/modules/agents/entities/skill.entity.ts new file mode 100644 index 00000000000..d7e8d96560b --- /dev/null +++ b/packages/cli/src/modules/agents/entities/skill.entity.ts @@ -0,0 +1,31 @@ +import { WithTimestamps } from '@n8n/db'; +import { Column, Entity, Index, PrimaryColumn } from '@n8n/typeorm'; + +/** How a skill was created: `ui` in the skills hub, `agent` from the agent builder or the migration. */ +export type SkillSource = 'ui' | 'agent'; + +/** + * A skill in the skills hub, identified by its id only. One target: `projectId` (a team + * or personal project, used by its agents), `agentId` (only that agent can use it; the + * project is the agent's), or neither (the instance). + * The name and content live in `SkillVersion` rows. + */ +@Entity({ name: 'skill' }) +export class Skill extends WithTimestamps { + @PrimaryColumn({ type: 'varchar', length: 36 }) + id: string; + + @Index() + @Column({ type: 'varchar', length: 36, nullable: true }) + projectId: string | null; + + @Index() + @Column({ type: 'varchar', length: 36, nullable: true }) + agentId: string | null; + + @Column({ type: 'varchar', length: 16 }) + source: SkillSource; + + @Column({ type: 'uuid', nullable: true }) + createdById: string | null; +} diff --git a/packages/cli/src/services/ownership-transfer/ownership-transfer.manifest.json b/packages/cli/src/services/ownership-transfer/ownership-transfer.manifest.json index 4fba8b13d67..c51720acc76 100644 --- a/packages/cli/src/services/ownership-transfer/ownership-transfer.manifest.json +++ b/packages/cli/src/services/ownership-transfer/ownership-transfer.manifest.json @@ -89,6 +89,11 @@ "path": "packages/cli/src/modules/promotions.ee/database/entities/promotion-connection-project.entity.ts", "reason": "Promotion configuration for the project (which connection it is linked to), not user data. Dropped via the projectId FK cascade when the source project is deleted, as in ownership-transfer flows." }, + { + "name": "Skill", + "path": "packages/cli/src/modules/agents/entities/skill.entity.ts", + "reason": "Project-scoped skills belong to the project's agents, which are not transferred either (see Agent); both are dropped via FK cascade. Instance skills carry no projectId." + }, { "name": "AiPreference", "path": "packages/@n8n/db/src/entities/ai-preference.ts", diff --git a/packages/cli/test/migration/1791818723687-create-skills-hub-tables.test.ts b/packages/cli/test/migration/1791818723687-create-skills-hub-tables.test.ts new file mode 100644 index 00000000000..abcdd5621c6 --- /dev/null +++ b/packages/cli/test/migration/1791818723687-create-skills-hub-tables.test.ts @@ -0,0 +1,265 @@ +import { + createTestMigrationContext, + initDbUpToMigration, + runSingleMigration, + type TestMigrationContext, +} from '@n8n/backend-test-utils'; +import { DbConnection } from '@n8n/db'; +import { Container } from '@n8n/di'; +import { DataSource } from '@n8n/typeorm'; +import { randomUUID } from 'node:crypto'; + +const migrationName = 'CreateSkillsHubTables1791818723687'; + +type Row = Record; + +describe('CreateSkillsHubTables migration', () => { + let context: TestMigrationContext; + + const insertRow = async (tableName: string, values: Row) => { + const columns = Object.keys(values); + await context.runQuery( + `INSERT INTO ${context.escape.tableName(tableName)} + (${columns.map((name) => context.escape.columnName(name)).join(', ')}) + VALUES (${columns.map((name) => `:${name}`).join(', ')})`, + values, + ); + }; + + const deleteRow = async (tableName: string, column: string, value: string) => { + await context.runQuery( + `DELETE FROM ${context.escape.tableName(tableName)} WHERE ${context.escape.columnName(column)} = :value`, + { value }, + ); + }; + + const countRows = async (tableName: string, column: string, value: string) => { + const rows = await context.runQuery>( + `SELECT COUNT(*) AS ${context.escape.columnName('count')} FROM ${context.escape.tableName(tableName)} + WHERE ${context.escape.columnName(column)} = :value`, + { value }, + ); + return Number(rows[0].count); + }; + + const insertUser = async () => { + const id = randomUUID(); + // Roles go in as parameters: the Postgres helper reads `:word` in a literal as one. + await insertRow('user', { + id, + email: `${id}@test.com`, + firstName: 'Test', + lastName: 'User', + password: 'hashed', + roleSlug: 'global:member', + createdAt: new Date(), + updatedAt: new Date(), + }); + return id; + }; + + const insertProject = async () => { + const id = randomUUID(); + await insertRow('project', { id, name: 'Skills hub project', type: 'team' }); + return id; + }; + + const insertAgent = async (projectId: string) => { + const id = randomUUID(); + await insertRow('agents', { + id, + name: 'Skills hub agent', + projectId, + integrations: '[]', + tools: '{}', + skills: '{}', + }); + return id; + }; + + const insertAgentVersion = async (agentId: string) => { + const versionId = randomUUID(); + await insertRow('agent_history', { versionId, agentId, author: 'Test User' }); + return versionId; + }; + + /** A skill with one version and one file. */ + const insertSkill = async ( + target: { projectId?: string; agentId?: string }, + createdById?: string, + ) => { + const skillId = `skill_${randomUUID().slice(0, 16)}`; + await insertRow('skill', { + id: skillId, + projectId: target.projectId ?? null, + agentId: target.agentId ?? null, + source: 'ui', + createdById: createdById ?? null, + }); + const versionId = randomUUID(); + await insertRow('skill_version', { + id: versionId, + skillId, + version: 1, + name: 'Brand voice', + description: 'Use when writing emails', + instructions: 'Write in a warm tone.', + contentHash: 'a'.repeat(64), + }); + await insertRow('skill_file', { + skillVersionId: versionId, + path: 'references/tone.md', + content: 'Examples', + }); + return { skillId, versionId }; + }; + + beforeAll(async () => { + await Container.get(DbConnection).init(); + const initial = createTestMigrationContext(Container.get(DataSource)); + try { + await initial.queryRunner.clearDatabase(); + } finally { + await initial.queryRunner.release(); + } + await initDbUpToMigration(migrationName); + await runSingleMigration(migrationName); + }); + + beforeEach(() => { + context = createTestMigrationContext(Container.get(DataSource)); + }); + + afterEach(async () => { + await context.queryRunner.release(); + }); + + afterAll(async () => { + await Container.get(DbConnection).close(); + }); + + it('keeps a project skill when its author is deleted and clears the author', async () => { + const authorId = await insertUser(); + const projectId = await insertProject(); + const { skillId } = await insertSkill({ projectId }, authorId); + + await deleteRow('user', 'id', authorId); + + const rows = await context.runQuery>( + `SELECT ${context.escape.columnName('createdById')} FROM ${context.escape.tableName('skill')} + WHERE ${context.escape.columnName('id')} = :skillId`, + { skillId }, + ); + expect(rows).toEqual([{ createdById: null }]); + }); + + it('deletes a project together with its skills and the agents that pin them', async () => { + const projectId = await insertProject(); + const agentId = await insertAgent(projectId); + const agentVersionId = await insertAgentVersion(agentId); + const agentSkill = await insertSkill({ agentId }); + const { skillId, versionId } = await insertSkill({ projectId }); + await insertRow('agent_skill_dependency', { agentId, skillId, skillVersionId: versionId }); + await insertRow('agent_version_skill_dependency', { + agentVersionId, + skillId, + skillVersionId: versionId, + }); + + await deleteRow('project', 'id', projectId); + + expect(await countRows('agents', 'id', agentId)).toBe(0); + expect(await countRows('skill', 'id', skillId)).toBe(0); + expect(await countRows('skill_version', 'skillId', skillId)).toBe(0); + expect(await countRows('skill_file', 'skillVersionId', versionId)).toBe(0); + expect(await countRows('agent_skill_dependency', 'skillId', skillId)).toBe(0); + expect(await countRows('agent_version_skill_dependency', 'skillId', skillId)).toBe(0); + // An agent skill has no projectId and goes through the agent. + expect(await countRows('skill', 'id', agentSkill.skillId)).toBe(0); + }); + + /** One agent with a published version, both pinning the same skill version. */ + const insertPinnedSkill = async () => { + const projectId = await insertProject(); + const agentId = await insertAgent(projectId); + const agentVersionId = await insertAgentVersion(agentId); + const { skillId, versionId } = await insertSkill({}); + await insertRow('agent_skill_dependency', { agentId, skillId, skillVersionId: versionId }); + await insertRow('agent_version_skill_dependency', { + agentVersionId, + skillId, + skillVersionId: versionId, + }); + return { projectId, agentId, agentVersionId, skillId, versionId }; + }; + + it('refuses to delete a skill version that agents pin', async () => { + const { projectId, skillId, versionId } = await insertPinnedSkill(); + + await expect(deleteRow('skill_version', 'id', versionId)).rejects.toThrow(); + expect(await countRows('skill_version', 'id', versionId)).toBe(1); + + await deleteRow('project', 'id', projectId); + await deleteRow('skill', 'id', skillId); + }); + + it('deletes a skill together with the pins on it, and keeps the agents', async () => { + const { projectId, agentId, agentVersionId, skillId } = await insertPinnedSkill(); + + // The service refuses to delete a skill in use. The database only keeps the rows consistent. + await deleteRow('skill', 'id', skillId); + + expect(await countRows('agent_skill_dependency', 'skillId', skillId)).toBe(0); + expect(await countRows('agent_version_skill_dependency', 'skillId', skillId)).toBe(0); + expect(await countRows('agents', 'id', agentId)).toBe(1); + expect(await countRows('agent_history', 'versionId', agentVersionId)).toBe(1); + + await deleteRow('project', 'id', projectId); + }); + + it('deletes an agent together with its own skills, and keeps project skills', async () => { + const projectId = await insertProject(); + const agentId = await insertAgent(projectId); + const agentVersionId = await insertAgentVersion(agentId); + const own = await insertSkill({ agentId }); + const shared = await insertSkill({ projectId }); + for (const { skillId, versionId } of [own, shared]) { + await insertRow('agent_skill_dependency', { agentId, skillId, skillVersionId: null }); + await insertRow('agent_version_skill_dependency', { + agentVersionId, + skillId, + skillVersionId: versionId, + }); + } + + await deleteRow('agents', 'id', agentId); + + expect(await countRows('skill', 'id', own.skillId)).toBe(0); + expect(await countRows('skill_version', 'skillId', own.skillId)).toBe(0); + expect(await countRows('skill_file', 'skillVersionId', own.versionId)).toBe(0); + expect(await countRows('skill', 'id', shared.skillId)).toBe(1); + expect(await countRows('agent_skill_dependency', 'skillId', shared.skillId)).toBe(0); + expect(await countRows('agent_version_skill_dependency', 'skillId', shared.skillId)).toBe(0); + + await deleteRow('project', 'id', projectId); + }); + + it('rejects an agent skill that also has a project', async () => { + const projectId = await insertProject(); + const agentId = await insertAgent(projectId); + + await expect(insertSkill({ projectId, agentId })).rejects.toThrow(); + + await deleteRow('project', 'id', projectId); + }); + + // New sources must not need a migration, so the column has no CHECK on its values. + it('accepts a source value the code does not use yet', async () => { + const id = `skill_${randomUUID().slice(0, 16)}`; + + await insertRow('skill', { id, source: 'github' }); + + expect(await countRows('skill', 'id', id)).toBe(1); + await deleteRow('skill', 'id', id); + }); +});