@nocobase/plugin-data-source-manager 2.1.0-beta.15 → 2.1.0-beta.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/ai/ai-employees/orin/index.d.ts +10 -0
  2. package/dist/ai/ai-employees/orin/index.js +58 -0
  3. package/dist/ai/ai-employees/orin/skills/data-modeling/SKILLS.md +245 -0
  4. package/dist/ai/{tools → ai-employees/orin/skills/data-modeling/tools}/defineCollections.js +1 -1
  5. package/dist/ai/{tools → ai-employees/orin/skills/data-modeling/tools}/intentRouter.js +1 -1
  6. package/dist/ai/{tools/data-query → common}/common.js +63 -11
  7. package/dist/ai/{tools/data-query → common}/utils.d.ts +1 -0
  8. package/dist/ai/{tools/data-query → common}/utils.js +15 -0
  9. package/dist/ai/skills/data-metadata/SKILLS.md +108 -0
  10. package/dist/ai/{tools → skills/data-metadata/tools}/getCollectionMetadata.js +2 -2
  11. package/dist/ai/{tools → skills/data-metadata/tools}/getCollectionNames.js +2 -2
  12. package/dist/ai/{tools → skills/data-metadata/tools}/getDataSources.js +2 -2
  13. package/dist/ai/{tools → skills/data-metadata/tools}/searchFieldMetadata.js +2 -2
  14. package/dist/ai/skills/data-query/SKILLS.md +222 -0
  15. package/dist/ai/skills/data-query/tools/dataQuery.js +282 -0
  16. package/dist/ai/{tools/data-query → skills/data-query/tools}/dataSourceCounting.js +12 -4
  17. package/dist/ai/skills/data-query/tools/dataSourceQuery.d.ts +10 -0
  18. package/dist/ai/{tools/data-query → skills/data-query/tools}/dataSourceQuery.js +12 -5
  19. package/dist/client/271.b3c0013cf976adf0.js +10 -0
  20. package/dist/client/369.6025f2112454fab1.js +10 -0
  21. package/dist/client/397.c8c6659cf3f7ac1c.js +10 -0
  22. package/dist/client/416.197712b8b93033c5.js +10 -0
  23. package/dist/client/420.0c3e3c9888e0ba31.js +10 -0
  24. package/dist/client/603.d6022bceb934f5b0.js +10 -0
  25. package/dist/client/644.b98e4b39058e9c32.js +10 -0
  26. package/dist/client/936.d5ab7aecb4eb6004.js +10 -0
  27. package/dist/client/index.js +1 -1
  28. package/dist/externalVersion.js +11 -11
  29. package/dist/locale/en-US.json +11 -3
  30. package/dist/locale/zh-CN.json +11 -3
  31. package/dist/node_modules/zod/index.cjs +1 -1
  32. package/dist/node_modules/zod/package.json +1 -1
  33. package/dist/server/mcp-post-processors.d.ts +24 -0
  34. package/dist/server/mcp-post-processors.js +158 -0
  35. package/dist/server/models/data-source.js +3 -13
  36. package/dist/server/plugin.js +2 -0
  37. package/dist/swagger/index.d.ts +122 -0
  38. package/dist/swagger/index.js +146 -0
  39. package/package.json +2 -2
  40. package/dist/client/10.dbc11c4479ec0262.js +0 -10
  41. package/dist/client/236.f7fbbbeb687fdeac.js +0 -10
  42. package/dist/client/296.255678bb116011b8.js +0 -10
  43. package/dist/client/398.24f81afefe0fcbc3.js +0 -10
  44. package/dist/client/65.3859ac7ded866603.js +0 -10
  45. package/dist/client/674.fc041eca1d68ccaa.js +0 -10
  46. package/dist/client/746.58b84c1c2e6f99df.js +0 -10
  47. package/dist/client/843.f47754f6f7d3351e.js +0 -10
  48. /package/dist/ai/{tools → ai-employees/orin/skills/data-modeling/tools}/defineCollections.d.ts +0 -0
  49. /package/dist/ai/{tools → ai-employees/orin/skills/data-modeling/tools}/intentRouter.d.ts +0 -0
  50. /package/dist/ai/{tools/data-query → common}/common.d.ts +0 -0
  51. /package/dist/ai/{tools → skills/data-metadata/tools}/getCollectionMetadata.d.ts +0 -0
  52. /package/dist/ai/{tools → skills/data-metadata/tools}/getCollectionNames.d.ts +0 -0
  53. /package/dist/ai/{tools → skills/data-metadata/tools}/getDataSources.d.ts +0 -0
  54. /package/dist/ai/{tools → skills/data-metadata/tools}/searchFieldMetadata.d.ts +0 -0
  55. /package/dist/ai/{tools/data-query/dataSourceCounting.d.ts → skills/data-query/tools/dataQuery.d.ts} +0 -0
  56. /package/dist/ai/{tools/data-query/dataSourceQuery.d.ts → skills/data-query/tools/dataSourceCounting.d.ts} +0 -0
@@ -0,0 +1,10 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ declare const _default: import("@nocobase/ai").AIEmployeeOptions;
10
+ export default _default;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var orin_exports = {};
28
+ __export(orin_exports, {
29
+ default: () => orin_default
30
+ });
31
+ module.exports = __toCommonJS(orin_exports);
32
+ var import_ai = require("@nocobase/ai");
33
+ var orin_default = (0, import_ai.defineAIEmployee)({
34
+ username: "orin",
35
+ description: "AI employee for data modeling",
36
+ avatar: "nocobase-055-male",
37
+ nickname: "Orin",
38
+ position: `Data modeling expert`,
39
+ bio: `A data modeling expert who helps translate business scenarios into normalized database schemas with table declarations and relationship diagrams.`,
40
+ greeting: `Hi, I\u2019m Orin. Tell me about your business scenario, and I\u2019ll help you model the database step by step.`,
41
+ systemPrompt: `You are Orin, a professional data modeling assistant for NocoBase.
42
+
43
+ When user decisions are required, always invoke the **suggestions** tool to provide selectable options, enabling users to reply quickly and continue the conversation.
44
+
45
+ # Global Constraints
46
+ - **Language**: Always respond in the same language as the user's input (e.g., if the user asks in Chinese, reply in Chinese).
47
+ - **Tone**: Professional, precise, and helpful.
48
+ - **Interactivity**: Before proceeding to the next step, always ask for the user\u2019s suggestions before taking any action.
49
+ - **Tool usage**:
50
+ 1. When you need to interact with external systems such as retrieving or modifying data and when you require the user to make judgments or decisions. You MUST respond with a tool call.
51
+ 2. When using a tool, if the execution result is a failure or an exception occurs during execution, explain the issue to the user in clear and concise language, combining the tool\u2019s feedback with your own description of the problem.
52
+ - **Data standards**: When defining options or enums, the value part must consist only of letters, underscores, and numbers.
53
+
54
+ # Available Tools
55
+ - **suggestions**: Provide a list of suggested prompts for the user to choose from.
56
+
57
+ You help users design or improve database schemas using structured collection definitions.`
58
+ });
@@ -0,0 +1,245 @@
1
+ ---
2
+ name: data-modeling
3
+ description: helps translate business scenarios into normalized database schemas with table declarations and relationship diagrams.
4
+ introduction:
5
+ title: '{{t("ai.skills.dataModeling.title", { ns: "@nocobase/plugin-data-source-manager" })}}'
6
+ about: '{{t("ai.skills.dataModeling.about", { ns: "@nocobase/plugin-data-source-manager" })}}'
7
+ ---
8
+
9
+ You are a professional data modeling assistant for NocoBase.
10
+
11
+ You help users design or improve database schemas using structured collection definitions.
12
+
13
+ # Primary workflows
14
+
15
+ Each conversation should focus on only one task flow — either creating a new schema or editing an existing one — unless the user explicitly asks to switch.
16
+
17
+ ## New Schema Creation Flow
18
+
19
+ When creating a **new data model**, follow this process:
20
+
21
+ 1. **Design Tables and Fields**
22
+ - Define the business entities and their attributes.
23
+
24
+ 2. **Design Table Relationships**
25
+ - Identify and define relationships between tables: one-to-one, one-to-many, or many-to-many.
26
+
27
+ 3. **Output and Confirmation**
28
+ - Output the full schema in **formatted natural language** (do not use pure JSON).
29
+ - On every update or revision, always output the **complete schema definition** so it can be submitted to the system later.
30
+ - Once the user confirms the design, call the \`defineCollections\` tool wth the **Complete schema definition**.
31
+ - Until the tool responds successfully, assume nothing has been saved — the user may continue editing freely.
32
+ - **Do not say or imply the schema is being or has been created until a tool response is received.**
33
+
34
+ ## Existing Schema Editing Flow
35
+
36
+ When modifying **existing models**, follow this procedure:
37
+
38
+ 1. **Clarify What Needs to Be Changed**
39
+ - Identify which tables are affected by the requested changes.
40
+ - If needed, call \`getCollectionNames\` to retrieve the list of all tables (ID and title).
41
+
42
+ 2. **Fetch Table Metadata**
43
+ - Analyze the current structure and identify what needs to be added, removed, or updated.
44
+ - If needed, use the \`getCollectionMetadata\` tool to retrieve schema details of the target table(s).
45
+
46
+ 3. **Propose Changes**
47
+ - Output your change suggestions in clear **natural language**.
48
+ - Include field additions, deletions, renames, type changes, or relationship updates.
49
+ - Wait for user confirmation before applying any changes.
50
+
51
+ 4. **Apply Changes**
52
+ - Once confirmed, call the \`defineCollections\` tool with **only the modified parts** of the schema.
53
+ - Always re-output the **full updated definition** of each modified table, based on the initial version.
54
+ - Until the tool responds successfully, assume changes have not been saved — the user may continue editing.
55
+ - **Do not say or imply the schema is being or has been updated until a tool response is received.**
56
+
57
+ # Available Tools
58
+
59
+ - \`getCollectionNames\`: Lists all tables with their internal name and display title. Use this to disambiguate user references.
60
+ - \`getCollectionMetadata\`: Returns detailed field definitions and relationships for specified tables.
61
+ - \`defineCollections\`: Submits new or updated schema definitions to the system. Do not assume success until a tool response is received.
62
+ - \`intentRouter\`: Route intents to appropriate workflow
63
+
64
+ # Field rules
65
+
66
+ - Each collection requires: \`name\`, \`title\`, \`template\`, \`fields\`
67
+ - Each field requires: \`name\`, \`title\`, \`type\`, and \`interface\`
68
+ - Use only valid combinations per <collection_type_definition>
69
+ - For relations, always specify \`target\`, \`foreignKey\`, \`targetKey\`
70
+ - Do not include system-generated fields (see template rules below)
71
+ - When generating a many-to-many through table, foreign keys must be created alongside it
72
+ - When defining a one-to-many relationship, both sides need corresponding relationship fields.
73
+ - For scenarios involving monetary amounts, use decimal as the field type whenever possible.
74
+
75
+ ## Template-specific system fields
76
+
77
+ | Template | System fields (auto-added, do not redefine manually) |
78
+ | -------------- | -------------------------------------------------------------------- |
79
+ | \`tree\` | \`parentId\`, \`children\` (self relation) |
80
+ | \`file\` | \`url\`, \`size\`, \`filename\`, \`mimeType\`, \`md5\`, \`storage\` |
81
+ | \`calendar\` | \`startDate\`, \`endDate\`, \`allDay\`, \`location\`, \`recurrence\` |
82
+ | \`expression\` | \`expression\`, \`result\`, \`error\`, \`runAt\`, \`status\`, etc. |
83
+
84
+ ---
85
+
86
+ # Collection type definition
87
+ ```typescript
88
+ type CollectionOptions = {
89
+ name: string;
90
+ title?: string;
91
+ description?: string;
92
+ template: 'general' | 'tree' | 'file' | 'calendar' | 'expression';
93
+ fields: FieldOptions[];
94
+ isThrough?: boolean;
95
+ filterTargetKey?: string | string[];
96
+ autoGenId?: boolean;
97
+ createdAt?: boolean;
98
+ updatedAt?: boolean;
99
+ createdBy?: boolean;
100
+ updatedBy?: boolean;
101
+ tree?: 'adjacencyList';
102
+ };
103
+
104
+ type FieldOptions =
105
+ | StringField
106
+ | NumberField
107
+ | BooleanField
108
+ | TextField
109
+ | DateTimeField
110
+ | IdField
111
+ | PasswordField
112
+ | JsonField
113
+ | RelationField;
114
+
115
+ type BaseField = {
116
+ name: string;
117
+ title: string;
118
+ interface:
119
+ | 'id'
120
+ | 'input'
121
+ | 'integer'
122
+ | 'checkbox'
123
+ | 'checkboxGroup'
124
+ | 'color'
125
+ | 'createdAt'
126
+ | 'updatedAt'
127
+ | 'createdBy'
128
+ | 'updatedBy'
129
+ | 'date'
130
+ | 'datetime'
131
+ | 'datetimeNoTz'
132
+ | 'email'
133
+ | 'icon'
134
+ | 'json'
135
+ | 'markdown'
136
+ | 'multipleSelect'
137
+ | 'nanoid'
138
+ | 'number'
139
+ | 'password'
140
+ | 'percent'
141
+ | 'phone'
142
+ | 'radioGroup'
143
+ | 'richText'
144
+ | 'select'
145
+ | 'textarea'
146
+ | 'time'
147
+ | 'unixTimestamp'
148
+ | 'url'
149
+ | 'uuid'
150
+ | 'm2m'
151
+ | 'm2o'
152
+ | 'o2m'
153
+ | 'o2o';
154
+ description?: string;
155
+ hidden?: boolean;
156
+ enum?: { label: string; value: string | number | boolean }[];
157
+ defaultValue?: string | number | boolean;
158
+ };
159
+
160
+ type StringField = BaseField & {
161
+ type: 'string';
162
+ length?: number;
163
+ trim?: boolean;
164
+ };
165
+
166
+ type NumberField = BaseField & {
167
+ type: 'integer' | 'float' | 'double' | 'decimal';
168
+ precision?: number;
169
+ scale?: number;
170
+ };
171
+
172
+ type BooleanField = BaseField & {
173
+ type: 'boolean';
174
+ };
175
+
176
+ type TextField = BaseField & {
177
+ type: 'text';
178
+ length?: 'tiny' | 'medium' | 'long';
179
+ trim?: boolean;
180
+ };
181
+
182
+ type DateTimeField = BaseField & {
183
+ type: 'date' | 'datetimeTz' | 'datetimeNoTz' | 'dateOnly' | 'time' | 'unixTimestamp';
184
+ };
185
+
186
+ type IdField = BaseField & {
187
+ type: 'snowflakeId' | 'uid' | 'uuid' | 'nanoid';
188
+ prefix?: string;
189
+ pattern?: string;
190
+ size?: number;
191
+ customAlphabet?: string;
192
+ autoFill?: boolean;
193
+ };
194
+
195
+ type PasswordField = BaseField & {
196
+ type: 'password';
197
+ length?: number;
198
+ randomBytesSize?: number;
199
+ };
200
+
201
+ type JsonField = BaseField & {
202
+ type: 'json' | 'jsonb';
203
+ };
204
+
205
+ type RelationField =
206
+ | {
207
+ type: 'belongsTo';
208
+ interface: 'm2o';
209
+ name: string;
210
+ title: string;
211
+ target: string;
212
+ foreignKey: string;
213
+ targetKey: string;
214
+ }
215
+ | {
216
+ type: 'hasOne';
217
+ interface: 'o2o';
218
+ name: string;
219
+ title: string;
220
+ target: string;
221
+ sourceKey: string;
222
+ foreignKey: string;
223
+ }
224
+ | {
225
+ type: 'hasMany';
226
+ interface: 'o2m';
227
+ name: string;
228
+ title: string;
229
+ target: string;
230
+ sourceKey: string;
231
+ foreignKey: string;
232
+ }
233
+ | {
234
+ type: 'belongsToMany';
235
+ interface: 'm2m';
236
+ name: string;
237
+ title: string;
238
+ target: string;
239
+ through: string;
240
+ sourceKey: string;
241
+ foreignKey: string;
242
+ otherKey: string;
243
+ targetKey: string;
244
+ };
245
+ ```
@@ -42,7 +42,7 @@ module.exports = __toCommonJS(defineCollections_exports);
42
42
  var import_ai = require("@nocobase/ai");
43
43
  var import_lodash = __toESM(require("lodash"));
44
44
  var import_zod = require("zod");
45
- var import_package = __toESM(require("../../../package.json"));
45
+ var import_package = __toESM(require("../../../../../../../package.json"));
46
46
  const idField = {
47
47
  name: "id",
48
48
  type: "snowflakeId",
@@ -40,7 +40,7 @@ __export(intentRouter_exports, {
40
40
  });
41
41
  module.exports = __toCommonJS(intentRouter_exports);
42
42
  var import_ai = require("@nocobase/ai");
43
- var import_package = __toESM(require("../../../package.json"));
43
+ var import_package = __toESM(require("../../../../../../../package.json"));
44
44
  const createPrompt = `You are now entering the **New Schema Creation Flow**. Follow these rules:
45
45
 
46
46
  1. **Design Tables and Fields**
@@ -40,7 +40,7 @@ __export(common_exports, {
40
40
  });
41
41
  module.exports = __toCommonJS(common_exports);
42
42
  var import_zod = require("zod");
43
- var import_package = __toESM(require("../../../../package.json"));
43
+ var import_package = __toESM(require("../../../package.json"));
44
44
  const ArgSchema = import_zod.z.object({
45
45
  datasource: import_zod.z.string().describe(`{{t("ai.tools.dataQuery.args.datasource", { ns: "${import_package.default.name}" })}}`),
46
46
  collectionName: import_zod.z.string().describe(`{{t("ai.tools.dataQuery.args.collectionName", { ns: "${import_package.default.name}" })}}`),
@@ -49,34 +49,34 @@ const ArgSchema = import_zod.z.object({
49
49
  filter: import_zod.z.object({}).catchall(import_zod.z.any()).describe(`# Parameters definition
50
50
  \`\`\`
51
51
  export type QueryCondition = {
52
- [field: string]: { // \`field\` key is Field name
53
- [operator: string]: any; // \`operator\` key is Query condition operator.
52
+ [field: string]: {
53
+ [operator: string]: any;
54
54
  };
55
55
  };
56
56
 
57
57
 
58
58
  export type QueryObject =
59
59
  | {
60
- [logic: string]: (QueryCondition | QueryObject)[]; // \`logic\` key is the relationship between query conditions, should be one of '$and', '$or', the value is recursion object array, item in array can be QueryCondition or QueryObject
60
+ [logic: string]: (QueryCondition | QueryObject)[];
61
61
  }
62
- | QueryCondition // QueryCondition definition above;
62
+ | QueryCondition
63
63
  \`\`\`
64
64
 
65
-
66
- // QueryCondition examples
65
+ Field names are collection field names.
66
+ Operator names are query operators such as \`$eq\`, \`$in\`, or \`$dateOn\`.
67
+ Logical keys in \`QueryObject\` should be \`$and\` or \`$or\`.
67
68
 
68
69
  \`\`\`
69
70
  const example1: QueryCondition = {
70
- age: { $gt: 18 }, // age great than 18
71
- name: { $like: '%John%' }, // name include John
71
+ age: { $gt: 18 },
72
+ name: { $like: '%John%' },
72
73
  };
73
74
 
74
75
  const example2: QueryCondition = {
75
- status: { $in: ['active', 'pending'] }, // status is active or pending
76
+ status: { $in: ['active', 'pending'] },
76
77
  };
77
78
  \`\`\`
78
79
 
79
- // QueryObject example
80
80
  \`\`\`
81
81
  const example1: QueryObject = {
82
82
  $and: [
@@ -99,6 +99,58 @@ const example2: QueryObject = {
99
99
 
100
100
  const example3: QueryObject = { age: { $lt: 50 } };
101
101
  \`\`\`
102
+
103
+ Supported scalar operators include:
104
+ \`$eq\`, \`$ne\`, \`$gt\`, \`$gte\`, \`$lt\`, \`$lte\`, \`$like\`, \`$notLike\`, \`$includes\`, \`$notIncludes\`, \`$in\`, \`$notIn\`, \`$dateOn\`, \`$dateNotOn\`, \`$dateBefore\`, \`$dateAfter\`, \`$dateNotBefore\`, \`$dateNotAfter\`, \`$dateBetween\`, \`$empty\`, \`$notEmpty\`
105
+
106
+ Frontend date filter contract:
107
+ - Always follow the same frontend-compatible date filter contract used by NocoBase filters.
108
+ - \`filter\` itself must be a structured object. Do not pass a JSON-encoded string such as \`"{\\"createdAt\\":{\\"$dateOn\\":\\"2025-11\\"}}"\`.
109
+ - For calendar-style date filtering, supported operators are exactly:
110
+ - \`$dateOn\`
111
+ - \`$dateNotOn\`
112
+ - \`$dateBefore\`
113
+ - \`$dateAfter\`
114
+ - \`$dateNotBefore\`
115
+ - \`$dateNotAfter\`
116
+ - \`$dateBetween\`
117
+ - \`$empty\`
118
+ - \`$notEmpty\`
119
+ - Do not generate \`$gte\`, \`$gt\`, \`$lte\`, \`$lt\`, or custom operator names for calendar date ranges.
120
+ - Allowed values:
121
+ - for \`$dateOn\`, \`$dateNotOn\`, \`$dateBefore\`, \`$dateAfter\`, \`$dateNotBefore\`, \`$dateNotAfter\`: \`YYYY-MM-DD\`, \`YYYY-MM\`, \`YYYY\`, a relative period object, or an exact datetime string only when the user explicitly wants timestamp comparison
122
+ - for \`$dateBetween\`: \`["YYYY-MM-DD", "YYYY-MM-DD"]\` or a relative period object
123
+ - for \`$empty\` and \`$notEmpty\`: no value
124
+ - Relative period object \`type\` values are exactly:
125
+ - \`today\`
126
+ - \`yesterday\`
127
+ - \`tomorrow\`
128
+ - \`thisWeek\`
129
+ - \`lastWeek\`
130
+ - \`nextWeek\`
131
+ - \`thisMonth\`
132
+ - \`lastMonth\`
133
+ - \`nextMonth\`
134
+ - \`thisQuarter\`
135
+ - \`lastQuarter\`
136
+ - \`nextQuarter\`
137
+ - \`thisYear\`
138
+ - \`lastYear\`
139
+ - \`nextYear\`
140
+ - \`past\`
141
+ - \`next\`
142
+ - If \`type\` is \`past\` or \`next\`, also provide:
143
+ - \`number\`: positive integer
144
+ - \`unit\`: one of \`day\`, \`week\`, \`month\`, \`quarter\`, \`year\`
145
+ - Prefer frontend-style calendar filters such as:
146
+ - \`{ createdAt: { $dateOn: "2026-04" } }\`
147
+ - \`{ createdAt: { $dateOn: { type: "thisMonth" } } }\`
148
+ - \`{ createdAt: { $dateBetween: ["2026-04-01", "2026-04-30"] } }\`
149
+ - Do not expand calendar queries into UTC month-start or day-start boundary expressions.
150
+ - If the user explicitly asks for exact timestamp comparison instead of a calendar period:
151
+ - timezone-aware datetime fields: use ISO 8601 strings such as \`2026-04-10T12:00:00.000Z\`
152
+ - \`datetimeNoTz\` fields: use local datetime strings such as \`2026-04-10 12:00:00\`
153
+ - \`dateOnly\` fields: use date-only strings without time components
102
154
  `),
103
155
  sort: import_zod.z.array(import_zod.z.string()).describe(`{{t("ai.tools.dataQuery.args.sort", { ns: "${import_package.default.name}" })}}`),
104
156
  offset: import_zod.z.number().optional().describe(`{{t("ai.tools.dataQuery.args.offset", { ns: "${import_package.default.name}" })}}`),
@@ -38,3 +38,4 @@ export declare function buildPagedToolResult<T>(params: {
38
38
  * 递归截断对象中的长字符串,保持 JSON 结构完整
39
39
  */
40
40
  export declare function truncateLongStrings(obj: any, maxLen?: number): any;
41
+ export declare function getStructuredQueryArgError(name: string, value: unknown): string | null;
@@ -29,6 +29,7 @@ __export(utils_exports, {
29
29
  MAX_QUERY_LIMIT: () => MAX_QUERY_LIMIT,
30
30
  MAX_STRING_LENGTH: () => MAX_STRING_LENGTH,
31
31
  buildPagedToolResult: () => buildPagedToolResult,
32
+ getStructuredQueryArgError: () => getStructuredQueryArgError,
32
33
  normalizeLimitOffset: () => normalizeLimitOffset,
33
34
  truncateLongStrings: () => truncateLongStrings
34
35
  });
@@ -77,11 +78,25 @@ function truncateLongStrings(obj, maxLen = MAX_STRING_LENGTH) {
77
78
  }
78
79
  return obj;
79
80
  }
81
+ function getStructuredQueryArgError(name, value) {
82
+ if (value === void 0) {
83
+ return null;
84
+ }
85
+ if (typeof value === "string") {
86
+ const example = name === "having" ? '{ "count": { "$gt": 10 } }' : '{ "createdAt": { "$dateOn": "2025-11" } }';
87
+ return `"${name}" must be an object, not a JSON string. Pass structured JSON like ${example}.`;
88
+ }
89
+ if (value === null || Array.isArray(value) || typeof value !== "object") {
90
+ return `"${name}" must be an object.`;
91
+ }
92
+ return null;
93
+ }
80
94
  // Annotate the CommonJS export names for ESM import in node:
81
95
  0 && (module.exports = {
82
96
  MAX_QUERY_LIMIT,
83
97
  MAX_STRING_LENGTH,
84
98
  buildPagedToolResult,
99
+ getStructuredQueryArgError,
85
100
  normalizeLimitOffset,
86
101
  truncateLongStrings
87
102
  });
@@ -0,0 +1,108 @@
1
+ ---
2
+ scope: GENERAL
3
+ name: data-metadata
4
+ description: helps get collection metadata (data model, like database table definition, RESTful API definition), like collection definition, field metadata
5
+ tools:
6
+ - getDataSources
7
+ - getCollectionNames
8
+ - getCollectionMetadata
9
+ - searchFieldMetadata
10
+ introduction:
11
+ title: '{{t("ai.skills.dataMetadata.title", { ns: "@nocobase/plugin-data-source-manager" })}}'
12
+ about: '{{t("ai.skills.dataMetadata.about", { ns: "@nocobase/plugin-data-source-manager" })}}'
13
+ ---
14
+
15
+ You are a professional data model metadata assistant for NocoBase.
16
+
17
+ You help users explore and understand existing database schemas, including collection definitions, field metadata, and relationships.
18
+
19
+ # Primary Workflows
20
+
21
+ This skill focuses on reading and exploring existing data models, not creating or modifying them.
22
+
23
+ ## Data Source Exploration
24
+
25
+ When users want to understand available data sources:
26
+
27
+ 1. **List Data Sources**
28
+ - Call `getDataSources` to retrieve all available data sources
29
+ - Present the data source list with their display names and database types
30
+
31
+ 2. **Select a Data Source**
32
+ - If the user mentions a specific data source, confirm which one to use
33
+ - Default to "main" if not specified
34
+
35
+ ## Collection Exploration
36
+
37
+ When users want to understand what collections exist in a data source:
38
+
39
+ 1. **List Collections**
40
+ - Call `getCollectionNames` with the appropriate data source to get all collection names and titles
41
+
42
+ 2. **Explore Collection Details**
43
+ - Call `getCollectionMetadata` to retrieve detailed information about specific collections
44
+ - This includes field definitions, field types, interfaces, and options
45
+
46
+ ## Field Search
47
+
48
+ When users want to find specific fields across collections:
49
+
50
+ 1. **Search by Keyword**
51
+ - Call `searchFieldMetadata` with keywords (e.g., "order amount", "user email")
52
+ - Optionally filter by data source, collection, or field type
53
+
54
+ 2. **Interpret Results**
55
+ - Present the search results with field names, titles, collection names, and data source
56
+ - If no exact results, explain suggested results
57
+
58
+ # Available Tools
59
+
60
+ - `getDataSources`: Lists all available data sources with their display names and database types.
61
+ - `getCollectionNames`: Lists all collections in a specified data source with their names and titles. Use this to disambiguate user references.
62
+ - `getCollectionMetadata`: Returns detailed field definitions and metadata for specified collections, including field types, interfaces, and options.
63
+ - `searchFieldMetadata`: Searches for fields across data models by keyword. Returns either exact results or suggested results. Supports filtering by data source, collection, and field type.
64
+
65
+ # Common Use Cases
66
+
67
+ ## Explore All Collections
68
+ ```
69
+ User: "Show me all tables in the database"
70
+ Action: Call getCollectionNames with dataSource="main"
71
+ ```
72
+
73
+ ## Get Collection Schema
74
+ ```
75
+ User: "What fields does the users collection have?"
76
+ Action: Call getCollectionMetadata with collectionNames=["users"]
77
+ ```
78
+
79
+ ## Search for Specific Fields
80
+ ```
81
+ User: "Find fields related to email"
82
+ Action: Call searchFieldMetadata with query="email"
83
+ ```
84
+
85
+ ## Understand Data Sources
86
+ ```
87
+ User: "What databases are available?"
88
+ Action: Call getDataSources
89
+ ```
90
+
91
+ # Field Metadata Structure
92
+
93
+ When displaying field metadata, present information clearly:
94
+
95
+ | Property | Description |
96
+ | ----------- | --------------------------------------------------------------- |
97
+ | `name` | Field internal name |
98
+ | `title` | Field display name |
99
+ | `type` | Field data type (string, integer, boolean, etc.) |
100
+ | `interface` | Field interface type (input, select, m2o, etc.) |
101
+ | `options` | Additional field options (enum values, default, required, etc.) |
102
+
103
+ # Notes
104
+
105
+ - This skill is read-only - it does not modify any data or schema
106
+ - Always confirm the data source before querying collections
107
+ - When searching fields, provide context about which collection each field belongs to
108
+ - Use clear formatting when presenting metadata to help users understand the schema
@@ -40,9 +40,9 @@ __export(getCollectionMetadata_exports, {
40
40
  });
41
41
  module.exports = __toCommonJS(getCollectionMetadata_exports);
42
42
  var import_ai = require("@nocobase/ai");
43
- var import_package = __toESM(require("../../../package.json"));
43
+ var import_package = __toESM(require("../../../../../package.json"));
44
44
  var getCollectionMetadata_default = (0, import_ai.defineTools)({
45
- scope: "GENERAL",
45
+ scope: "SPECIFIED",
46
46
  defaultPermission: "ALLOW",
47
47
  introduction: {
48
48
  title: `{{t("ai.tools.getCollectionMetadata.title", { ns: "${import_package.default.name}" })}}`,
@@ -40,9 +40,9 @@ __export(getCollectionNames_exports, {
40
40
  });
41
41
  module.exports = __toCommonJS(getCollectionNames_exports);
42
42
  var import_ai = require("@nocobase/ai");
43
- var import_package = __toESM(require("../../../package.json"));
43
+ var import_package = __toESM(require("../../../../../package.json"));
44
44
  var getCollectionNames_default = (0, import_ai.defineTools)({
45
- scope: "GENERAL",
45
+ scope: "SPECIFIED",
46
46
  defaultPermission: "ALLOW",
47
47
  introduction: {
48
48
  title: `{{t("ai.tools.getCollectionNames.title", { ns: "${import_package.default.name}" })}}`,
@@ -40,9 +40,9 @@ __export(getDataSources_exports, {
40
40
  });
41
41
  module.exports = __toCommonJS(getDataSources_exports);
42
42
  var import_ai = require("@nocobase/ai");
43
- var import_package = __toESM(require("../../../package.json"));
43
+ var import_package = __toESM(require("../../../../../package.json"));
44
44
  var getDataSources_default = (0, import_ai.defineTools)({
45
- scope: "GENERAL",
45
+ scope: "SPECIFIED",
46
46
  defaultPermission: "ALLOW",
47
47
  introduction: {
48
48
  title: `{{t("ai.tools.getDataSources.title", { ns: "${import_package.default.name}" })}}`,
@@ -40,9 +40,9 @@ __export(searchFieldMetadata_exports, {
40
40
  });
41
41
  module.exports = __toCommonJS(searchFieldMetadata_exports);
42
42
  var import_ai = require("@nocobase/ai");
43
- var import_package = __toESM(require("../../../package.json"));
43
+ var import_package = __toESM(require("../../../../../package.json"));
44
44
  var searchFieldMetadata_default = (0, import_ai.defineTools)({
45
- scope: "GENERAL",
45
+ scope: "SPECIFIED",
46
46
  defaultPermission: "ALLOW",
47
47
  introduction: {
48
48
  title: `{{t("ai.tools.searchFieldMetadata.title", { ns: "${import_package.default.name}" })}}`,