@nocobase/plugin-ai 3.0.0-alpha.3 → 3.0.0-alpha.5
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.
- package/dist/ai/docs/nocobase/ai-employees/dev/ai-employee/complete-example.md +206 -0
- package/dist/ai/docs/nocobase/ai-employees/dev/ai-employee/define-ai-employee.md +149 -0
- package/dist/ai/docs/nocobase/ai-employees/dev/ai-employee/define-skill.md +138 -0
- package/dist/ai/docs/nocobase/ai-employees/dev/ai-employee/define-tool.md +189 -0
- package/dist/ai/docs/nocobase/ai-employees/dev/ai-employee/frontend-tool-ui.md +296 -0
- package/dist/ai/docs/nocobase/ai-employees/dev/ai-employee/index.md +126 -0
- package/dist/ai/docs/nocobase/ai-employees/dev/ai-employee/internationalization.md +88 -0
- package/dist/ai/docs/nocobase/ai-employees/dev/ai-employee/troubleshooting.md +86 -0
- package/dist/ai/docs/nocobase/ai-employees/{knowledge-base/dev → dev/knowledge-base}/external-knowledge-base.md +2 -2
- package/dist/ai/docs/nocobase/ai-employees/knowledge-base/knowledge-base/index.md +1 -1
- package/dist/ai/docs/nocobase/development/index.md +1 -1
- package/dist/client/{244.8631eb5cf3f05e21.js → 244.145eb763339a109b.js} +1 -1
- package/dist/client/{264.cc98933ef65608b6.js → 264.6ca5f2eeb4173d86.js} +1 -1
- package/dist/client/index.js +2 -2
- package/dist/client-v2/{244.c428e645ecb94414.js → 244.64cb9d3ee27dcdc6.js} +1 -1
- package/dist/client-v2/{264.be92ff6a4d2612f1.js → 264.3c7d8e90aa7f46ee.js} +1 -1
- package/dist/client-v2/index.js +2 -2
- package/dist/client-v2/pages/LLMServicesPage.d.ts +9 -4
- package/dist/externalVersion.js +15 -15
- package/dist/locale/de-DE.json +2 -1
- package/dist/locale/en-US.json +3 -1
- package/dist/locale/es-ES.json +2 -1
- package/dist/locale/fr-FR.json +2 -1
- package/dist/locale/hu-HU.json +2 -1
- package/dist/locale/id-ID.json +2 -1
- package/dist/locale/it-IT.json +2 -1
- package/dist/locale/ja-JP.json +2 -1
- package/dist/locale/ko-KR.json +2 -1
- package/dist/locale/nl-NL.json +2 -1
- package/dist/locale/pt-BR.json +2 -1
- package/dist/locale/ru-RU.json +2 -1
- package/dist/locale/tr-TR.json +2 -1
- package/dist/locale/uk-UA.json +2 -1
- package/dist/locale/vi-VN.json +2 -1
- package/dist/locale/zh-CN.json +3 -1
- package/dist/locale/zh-TW.json +2 -1
- package/dist/node_modules/@langchain/mistralai/package.json +1 -1
- package/dist/node_modules/@langchain/xai/package.json +1 -1
- package/dist/node_modules/fs-extra/package.json +1 -1
- package/dist/node_modules/jsonrepair/package.json +1 -1
- package/dist/node_modules/just-bash/package.json +1 -1
- package/dist/node_modules/nodejs-snowflake/package.json +1 -1
- package/dist/node_modules/openai/package.json +1 -1
- package/dist/node_modules/zod/package.json +1 -1
- package/dist/swagger/index.d.ts +8 -0
- package/dist/swagger/llm.d.ts +8 -0
- package/dist/swagger/llm.js +8 -0
- package/package.json +2 -2
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Complete Example: Create a Built-in AI Employee"
|
|
3
|
+
description: "Use a complete example to define a Tool, Skill, system prompt, and built-in AI employee in a NocoBase plugin."
|
|
4
|
+
keywords: "NocoBase,Dev Helper,AI employee example,defineTools,defineAIEmployee,SKILLS.md"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Complete Example: Create a Built-in AI Employee
|
|
8
|
+
|
|
9
|
+
The following complete example creates a built-in AI employee that guides plugin development. The example names the employee `Dev Helper` and configures its Tool, Skill, and system prompt. When a user says “Please greet Alice,” the employee loads the `welcome-developer` Skill, calls the `greetDeveloper` Tool to confirm the name, and then generates a greeting in the user's current language.
|
|
10
|
+
|
|
11
|
+
:::tip Prerequisites
|
|
12
|
+
|
|
13
|
+
- [Define a server-side Tool](./define-tool.md) — Learn the basic structure of `defineTools()` and Tools
|
|
14
|
+
- [Define a Skill](./define-skill.md) — Learn about `SKILLS.md` and Tool binding
|
|
15
|
+
- [Define a built-in AI employee](./define-ai-employee.md) — Learn about `defineAIEmployee()` and employee directories
|
|
16
|
+
|
|
17
|
+
:::
|
|
18
|
+
|
|
19
|
+
## Final result
|
|
20
|
+
|
|
21
|
+
When complete, the plugin provides these capabilities:
|
|
22
|
+
|
|
23
|
+
- Creates a built-in AI employee named `Dev Helper`
|
|
24
|
+
- Automatically binds the `welcome-developer` Skill to the employee
|
|
25
|
+
- Uses the Skill to call the `greetDeveloper` Tool and confirm the developer's name
|
|
26
|
+
- Generates a greeting and follow-up question in the user's current language
|
|
27
|
+
|
|
28
|
+
<!-- 需要一张 AI 员工管理页中 Dev Helper 被标记为内置员工的截图 -->
|
|
29
|
+
|
|
30
|
+
## Final directory structure
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
src/ai/ai-employees/dev-helper/
|
|
34
|
+
├── index.ts
|
|
35
|
+
├── prompt.md
|
|
36
|
+
└── skills/
|
|
37
|
+
└── welcome-developer/
|
|
38
|
+
├── SKILLS.md
|
|
39
|
+
└── tools/
|
|
40
|
+
└── greetDeveloper.ts
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
This example requires no frontend code and no manual registration in `src/server/plugin.ts`.
|
|
44
|
+
|
|
45
|
+
## Step 1: Define the Tool
|
|
46
|
+
|
|
47
|
+
Create `src/ai/ai-employees/dev-helper/skills/welcome-developer/tools/greetDeveloper.ts`:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import type { Context } from '@nocobase/actions';
|
|
51
|
+
import { defineTools } from '@nocobase/ai';
|
|
52
|
+
import { z } from 'zod';
|
|
53
|
+
|
|
54
|
+
export default defineTools({
|
|
55
|
+
scope: 'SPECIFIED',
|
|
56
|
+
defaultPermission: 'ALLOW',
|
|
57
|
+
introduction: {
|
|
58
|
+
title: '{{t("ai.tools.greetDeveloper.title", { ns: "@nocobase/plugin-developer-helper" })}}',
|
|
59
|
+
about: '{{t("ai.tools.greetDeveloper.about", { ns: "@nocobase/plugin-developer-helper" })}}',
|
|
60
|
+
},
|
|
61
|
+
definition: {
|
|
62
|
+
name: 'greetDeveloper',
|
|
63
|
+
description: 'Validate the developer name before the assistant writes a welcome message.',
|
|
64
|
+
schema: z.object({
|
|
65
|
+
name: z.string().min(1).describe('The developer name provided by the user.'),
|
|
66
|
+
}),
|
|
67
|
+
},
|
|
68
|
+
invoke: async (_ctx: Context, args: { name: string }) => {
|
|
69
|
+
return {
|
|
70
|
+
status: 'success',
|
|
71
|
+
content: {
|
|
72
|
+
name: args.name,
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Step 2: Define the Skill
|
|
80
|
+
|
|
81
|
+
Create `src/ai/ai-employees/dev-helper/skills/welcome-developer/SKILLS.md`:
|
|
82
|
+
|
|
83
|
+
```md
|
|
84
|
+
---
|
|
85
|
+
scope: SPECIFIED
|
|
86
|
+
name: welcome-developer
|
|
87
|
+
description: Greet a developer by name and guide them to the next NocoBase plugin-development step.
|
|
88
|
+
introduction:
|
|
89
|
+
title: '{{t("ai.skills.welcomeDeveloper.title", { ns: "@nocobase/plugin-developer-helper" })}}'
|
|
90
|
+
about: '{{t("ai.skills.welcomeDeveloper.about", { ns: "@nocobase/plugin-developer-helper" })}}'
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
You welcome developers who are starting NocoBase plugin development.
|
|
94
|
+
|
|
95
|
+
# Workflow
|
|
96
|
+
|
|
97
|
+
1. Read the developer name from the user's request.
|
|
98
|
+
2. If the name is missing, ask the user for it.
|
|
99
|
+
3. Call `greetDeveloper` exactly once.
|
|
100
|
+
4. Wait for a tool result with `status: "success"`.
|
|
101
|
+
5. Use `content.name` to write a short welcome message in the same language as the user.
|
|
102
|
+
6. Ask which plugin capability the developer wants to build next, using the same language as the user.
|
|
103
|
+
|
|
104
|
+
# Constraints
|
|
105
|
+
|
|
106
|
+
- Do not invent a name.
|
|
107
|
+
- Do not claim the Tool succeeded before receiving its result.
|
|
108
|
+
- Write both the welcome message and the follow-up question in the same language as the user.
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Because `greetDeveloper.ts` is in the current Skill's `tools/` directory, you do not need to add `tools: [greetDeveloper]`.
|
|
112
|
+
|
|
113
|
+
## Step 3: Define the AI employee profile
|
|
114
|
+
|
|
115
|
+
Create `src/ai/ai-employees/dev-helper/index.ts`:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import { defineAIEmployee } from '@nocobase/ai';
|
|
119
|
+
|
|
120
|
+
export default defineAIEmployee({
|
|
121
|
+
username: 'developer-helper-dev-assistant',
|
|
122
|
+
category: 'developer',
|
|
123
|
+
description: 'AI employee for helping developers start NocoBase plugin development.',
|
|
124
|
+
avatar: 'nocobase-002-male',
|
|
125
|
+
nickname: 'Dev Helper',
|
|
126
|
+
position: 'Plugin development guide',
|
|
127
|
+
bio: 'Welcomes developers and guides them into a small, verifiable plugin-development task.',
|
|
128
|
+
greeting: 'Hello, I can help you begin a NocoBase plugin development task. Who are we welcoming today?',
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`username` is the unique identifier in the database. Do not change it casually after release, or NocoBase will treat the new value as a different built-in AI employee.
|
|
133
|
+
|
|
134
|
+
:::warning Note
|
|
135
|
+
|
|
136
|
+
The `username` must remain stable and must not conflict with another plugin or existing AI employee. If the database already contains the same `username`, loading the plugin updates that record instead of creating an isolated new employee.
|
|
137
|
+
|
|
138
|
+
When the plugin reloads, the `category`, `nickname`, `position`, `avatar`, `bio`, `greeting`, default system prompt, Skill and Tool bindings, `chatSettings`, and `sort` from the code may all be written to the database again. For production plugins, use a plugin-prefixed name such as `developer-helper-dev-assistant`.
|
|
139
|
+
|
|
140
|
+
:::
|
|
141
|
+
|
|
142
|
+
## Step 4: Define the system prompt
|
|
143
|
+
|
|
144
|
+
Create `src/ai/ai-employees/dev-helper/prompt.md`:
|
|
145
|
+
|
|
146
|
+
```md
|
|
147
|
+
You are Dev Helper, a NocoBase plugin development guide.
|
|
148
|
+
|
|
149
|
+
Help users begin with a small, verifiable task.
|
|
150
|
+
|
|
151
|
+
When the user asks you to greet or welcome a developer, load the `welcome-developer` skill and follow its workflow.
|
|
152
|
+
|
|
153
|
+
Never claim that a Tool succeeded before receiving its result.
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The directory relationships now provide automatic binding:
|
|
157
|
+
|
|
158
|
+
```text
|
|
159
|
+
greetDeveloper Tool
|
|
160
|
+
→ welcome-developer Skill
|
|
161
|
+
→ dev-helper AI employee
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Step 5: Enable and verify
|
|
165
|
+
|
|
166
|
+
Rebuild or restart the development service and confirm that the plugin containing these files is enabled. Then check the AI employee management page:
|
|
167
|
+
|
|
168
|
+
- `Dev Helper` is listed
|
|
169
|
+
- The employee is marked as built-in
|
|
170
|
+
- The employee's dedicated Skills include `welcome-developer`
|
|
171
|
+
- `greetDeveloper` is available after the Skill loads
|
|
172
|
+
|
|
173
|
+
Enter the following in a conversation:
|
|
174
|
+
|
|
175
|
+
```text
|
|
176
|
+
请向 Alice 打个招呼。
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The expected sequence is:
|
|
180
|
+
|
|
181
|
+
```text
|
|
182
|
+
加载 welcome-developer
|
|
183
|
+
→ 调用 greetDeveloper({ name: "Alice" })
|
|
184
|
+
→ 收到 status: "success" 和 content.name
|
|
185
|
+
→ Skill 使用用户当前语言生成问候语
|
|
186
|
+
→ 询问接下来要开发什么插件能力
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Set `defaultPermission: 'ALLOW'` if the Tool should not ask the user for confirmation before every call. For Tools that delete data, modify records in bulk, or have external side effects, keeping the default `ASK` is more appropriate.
|
|
190
|
+
|
|
191
|
+
## Summary
|
|
192
|
+
|
|
193
|
+
| File | Responsibility |
|
|
194
|
+
| --- | --- |
|
|
195
|
+
| `greetDeveloper.ts` | Validates input and returns a structured Tool result |
|
|
196
|
+
| `SKILLS.md` | Defines the Tool call and response workflow |
|
|
197
|
+
| `prompt.md` | Defines the employee role and global constraints |
|
|
198
|
+
| `index.ts` | Defines the built-in AI employee profile |
|
|
199
|
+
|
|
200
|
+
## Related links
|
|
201
|
+
|
|
202
|
+
- [AI employee plugin development](./index.md) — Understand the relationship between Tools, Skills, and built-in AI employees
|
|
203
|
+
- [Define a server-side Tool](./define-tool.md) — See the complete `defineTools()` configuration
|
|
204
|
+
- [Define a Skill](./define-skill.md) — See the fields and format of `SKILLS.md`
|
|
205
|
+
- [Define a built-in AI employee](./define-ai-employee.md) — Learn about `defineAIEmployee()` and directory binding
|
|
206
|
+
- [Internationalization for AI employee plugins](./internationalization.md) — Add translations for management-interface text in this example
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Define a Built-in AI Employee"
|
|
3
|
+
description: "Explains how NocoBase plugins use defineAIEmployee, prompt.md, skills, and tools directories to create built-in AI employees."
|
|
4
|
+
keywords: "NocoBase,built-in AI employee,defineAIEmployee,prompt.md,AIEmployeeOptions,Nathan"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Define a Built-in AI Employee
|
|
8
|
+
|
|
9
|
+
A built-in AI employee is registered with its plugin. When the plugin loads for the first time, NocoBase creates the corresponding employee record and marks it as built-in. On later plugin loads, the employee's default profile, prompt, Skills, and Tools are updated from the code.
|
|
10
|
+
|
|
11
|
+
## Single-file and directory forms
|
|
12
|
+
|
|
13
|
+
Use a single file when the profile is simple and does not need a separate prompt or dedicated resources:
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
src/ai/ai-employees/lina.ts
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Use a directory when you need `prompt.md`, dedicated Skills, or dedicated Tools:
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
src/ai/ai-employees/nathan/
|
|
23
|
+
├── index.ts
|
|
24
|
+
├── prompt.md
|
|
25
|
+
├── skills/
|
|
26
|
+
└── tools/
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The directory form is better suited to long-term maintenance.
|
|
30
|
+
|
|
31
|
+
## Use `defineAIEmployee()`
|
|
32
|
+
|
|
33
|
+
In `index.ts`, use `defineAIEmployee()` from `@nocobase/ai`:
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { defineAIEmployee } from '@nocobase/ai';
|
|
37
|
+
|
|
38
|
+
export default defineAIEmployee({
|
|
39
|
+
username: 'developer-helper-dev-assistant',
|
|
40
|
+
category: 'developer',
|
|
41
|
+
description: 'AI employee for helping developers start NocoBase plugin development.',
|
|
42
|
+
avatar: 'nocobase-002-male',
|
|
43
|
+
nickname: 'Dev Helper',
|
|
44
|
+
position: 'Plugin development guide',
|
|
45
|
+
bio: 'Helps developers understand plugin structure and complete small development tasks.',
|
|
46
|
+
greeting: 'Hello, I can help you start a NocoBase plugin development task. What would you like to build?',
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The main fields are:
|
|
51
|
+
|
|
52
|
+
| Field | Purpose |
|
|
53
|
+
| --- | --- |
|
|
54
|
+
| `username` | Unique AI employee identifier; required and must remain stable over time |
|
|
55
|
+
| `category` | Employee category, such as `developer` or `business` |
|
|
56
|
+
| `description` | Internal description and retrieval information |
|
|
57
|
+
| `avatar` | Avatar identifier |
|
|
58
|
+
| `nickname` | Name displayed to users |
|
|
59
|
+
| `position` | Job title |
|
|
60
|
+
| `bio` | Short biography |
|
|
61
|
+
| `greeting` | Greeting for a new conversation |
|
|
62
|
+
| `systemPrompt` | Default system prompt |
|
|
63
|
+
| `skills` | Explicitly bound Skill names |
|
|
64
|
+
| `tools` | Explicitly bound Tool configuration |
|
|
65
|
+
| `chatSettings` | Chat settings such as whether Skills and Tools are enabled and which system-prompt mode is used |
|
|
66
|
+
| `sort` | Sort order for built-in employees |
|
|
67
|
+
|
|
68
|
+
The current type of `tools` is an array of objects:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
tools: [
|
|
72
|
+
{ name: 'greetDeveloper' },
|
|
73
|
+
{ name: 'customDataExporter', autoCall: true }, // customDataExporter 的 scope 必须是 CUSTOM
|
|
74
|
+
]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`autoCall` only overrides the current AI employee's call permission for a `CUSTOM` Tool. For `GENERAL` and `SPECIFIED` Tools, runtime behavior still follows the Tool's own `defaultPermission`. If a `CUSTOM` Tool has no employee-level configuration, it also falls back to the Tool's own `defaultPermission`.
|
|
78
|
+
|
|
79
|
+
Tools discovered automatically in the directory are normalized to `{ name: 'toolName' }`.
|
|
80
|
+
|
|
81
|
+
## Put long prompts in `prompt.md`
|
|
82
|
+
|
|
83
|
+
When an AI employee uses the directory form, put its system prompt in the sibling `prompt.md` file:
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
src/ai/ai-employees/dev-helper/prompt.md
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
```md
|
|
90
|
+
You are Dev Helper, a NocoBase plugin development guide.
|
|
91
|
+
|
|
92
|
+
Help the user break a plugin requirement into small, verifiable steps.
|
|
93
|
+
|
|
94
|
+
When the user asks you to welcome a developer, load the `welcome-developer` skill and follow it.
|
|
95
|
+
|
|
96
|
+
Never claim that a Tool succeeded before receiving its result.
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
When `prompt.md` exists, it overrides `systemPrompt` in `index.ts`. Long prompts are easier to review in a Markdown file and avoid escaping problems in TypeScript template strings.
|
|
100
|
+
|
|
101
|
+
## Built-in AI employee example: Nathan
|
|
102
|
+
|
|
103
|
+
The employee profile in `packages/plugins/@nocobase/plugin-flow-engine/src/ai/ai-employees/nathan/index.ts` is short:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
export default defineAIEmployee({
|
|
107
|
+
username: 'nathan',
|
|
108
|
+
category: 'developer',
|
|
109
|
+
description: 'AI employee for coding',
|
|
110
|
+
avatar: 'nocobase-002-male',
|
|
111
|
+
nickname: 'Nathan',
|
|
112
|
+
position: 'Frontend code engineer',
|
|
113
|
+
greeting: 'Hello, I’m Nathan, your frontend code engineer...',
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Nathan's full capabilities come from other resources in the same directory:
|
|
118
|
+
|
|
119
|
+
```text
|
|
120
|
+
nathan/
|
|
121
|
+
├── index.ts
|
|
122
|
+
├── prompt.md
|
|
123
|
+
└── skills/
|
|
124
|
+
└── frontend-developer/
|
|
125
|
+
├── SKILLS.md
|
|
126
|
+
└── tools/
|
|
127
|
+
├── getContextApis.ts
|
|
128
|
+
├── getContextEnvs.ts
|
|
129
|
+
├── getContextVars.ts
|
|
130
|
+
├── lintAndTestJS.ts
|
|
131
|
+
├── patchJSCode.ts
|
|
132
|
+
├── readJSCode.ts
|
|
133
|
+
└── writeJSCode.ts
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
The loading process automatically completes three levels of binding:
|
|
137
|
+
|
|
138
|
+
1. Files in `tools/` are registered as Tools
|
|
139
|
+
2. The Tools are automatically bound to the `frontend-developer` Skill
|
|
140
|
+
3. The Skill is automatically bound to Nathan
|
|
141
|
+
|
|
142
|
+
As a result, `index.ts` does not need to list the complete `skills` and `tools` configuration again.
|
|
143
|
+
|
|
144
|
+
## Related links
|
|
145
|
+
|
|
146
|
+
- [AI employee plugin development](./index.md) — Understand the relationship between built-in AI employees, Tools, and Skills
|
|
147
|
+
- [Define a Skill](./define-skill.md) — Create a dedicated Skill for an employee
|
|
148
|
+
- [Complete example: Create a built-in AI employee](./complete-example.md) — See the complete employee directory and registration process
|
|
149
|
+
- [Internationalization for AI employee plugins](./internationalization.md) — Learn how localization differs for employee profiles and Tool and Skill text
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Define a Skill"
|
|
3
|
+
description: "Explains the frontmatter, prompt content, Tool binding, and automatic directory discovery for NocoBase AI employee SKILLS.md files."
|
|
4
|
+
keywords: "NocoBase,AI employee Skill,SKILLS.md,Skill Tool binding,business-analysis-report"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Define a Skill
|
|
8
|
+
|
|
9
|
+
A Skill does not execute code. It is an operating guide provided to the model that specifies the workflow, available Tools, validation steps, and output requirements.
|
|
10
|
+
|
|
11
|
+
## Skill directory
|
|
12
|
+
|
|
13
|
+
Each Skill uses its own directory:
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
src/ai/skills/business-analysis-report/
|
|
17
|
+
├── SKILLS.md
|
|
18
|
+
└── tools/
|
|
19
|
+
└── businessReportGenerator.ts
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Where:
|
|
23
|
+
|
|
24
|
+
- `SKILLS.md` defines metadata and prompt content
|
|
25
|
+
- `tools/` contains Tools used only with this Skill
|
|
26
|
+
- Tools discovered in `tools/` are automatically added to this Skill's Tool list
|
|
27
|
+
|
|
28
|
+
## `SKILLS.md` frontmatter
|
|
29
|
+
|
|
30
|
+
A minimal Skill looks like this:
|
|
31
|
+
|
|
32
|
+
```md
|
|
33
|
+
---
|
|
34
|
+
scope: SPECIFIED
|
|
35
|
+
name: welcome-developer
|
|
36
|
+
description: Greet a developer by name and explain the next step for starting NocoBase plugin development.
|
|
37
|
+
introduction:
|
|
38
|
+
title: '{{t("ai.skills.welcomeDeveloper.title", { ns: "@nocobase/plugin-developer-helper" })}}'
|
|
39
|
+
about: '{{t("ai.skills.welcomeDeveloper.about", { ns: "@nocobase/plugin-developer-helper" })}}'
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
You help welcome developers who are starting NocoBase plugin development.
|
|
43
|
+
|
|
44
|
+
When the user asks you to greet or welcome a developer:
|
|
45
|
+
|
|
46
|
+
1. Extract the developer name from the request.
|
|
47
|
+
2. Call `greetDeveloper` exactly once.
|
|
48
|
+
3. Return the greeting from the tool result.
|
|
49
|
+
4. Ask which plugin capability the developer wants to build next.
|
|
50
|
+
|
|
51
|
+
Do not claim that the greeting was generated until the tool returns `status: "success"`.
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Common frontmatter fields include:
|
|
55
|
+
|
|
56
|
+
| Field | Purpose |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| `scope` | Availability scope of the Skill; defaults to `SPECIFIED` when omitted |
|
|
59
|
+
| `name` | Unique name of the Skill |
|
|
60
|
+
| `description` | Helps the model decide when to load this Skill |
|
|
61
|
+
| `introduction.title` | Title displayed in the management interface |
|
|
62
|
+
| `introduction.about` | Description displayed in the management interface |
|
|
63
|
+
| `tools` | List of additional Tool names to bind |
|
|
64
|
+
|
|
65
|
+
The Skill content is stored unchanged and added to the model context after the Skill is loaded. Focus the content on workflow and constraints; do not copy Tool implementation details into it.
|
|
66
|
+
|
|
67
|
+
## Bind Tools to a Skill
|
|
68
|
+
|
|
69
|
+
There are two methods.
|
|
70
|
+
|
|
71
|
+
The first is to declare them explicitly in the frontmatter:
|
|
72
|
+
|
|
73
|
+
```yaml
|
|
74
|
+
tools:
|
|
75
|
+
- getSkill
|
|
76
|
+
- businessReportGenerator
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The second is to put the Tool in the current Skill's `tools/` directory:
|
|
80
|
+
|
|
81
|
+
```text
|
|
82
|
+
src/ai/skills/welcome-developer/
|
|
83
|
+
├── SKILLS.md
|
|
84
|
+
└── tools/
|
|
85
|
+
└── greetDeveloper.ts
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The loader automatically discovers `greetDeveloper` and merges it into the Skill's Tool list. By default, put a Tool that belongs exclusively to one Skill under that Skill's directory. The file location then expresses the binding relationship.
|
|
89
|
+
|
|
90
|
+
## How to write an effective Skill
|
|
91
|
+
|
|
92
|
+
A practical Skill usually includes:
|
|
93
|
+
|
|
94
|
+
1. Role and task boundaries
|
|
95
|
+
2. Required processing order
|
|
96
|
+
3. Which Tool to call at each step
|
|
97
|
+
4. When to ask the user for confirmation
|
|
98
|
+
5. How to handle Tool failures
|
|
99
|
+
6. Final output structure and validation conditions
|
|
100
|
+
|
|
101
|
+
If a Tool modifies data, the Skill must explicitly require the model to wait for a successful Tool result. It must not claim that the operation is complete before the call returns.
|
|
102
|
+
|
|
103
|
+
## Built-in Skill example: `business-analysis-report`
|
|
104
|
+
|
|
105
|
+
`packages/plugins/@nocobase/plugin-ai/src/ai/skills/business-analysis-report/SKILLS.md` breaks business analysis into a clear workflow:
|
|
106
|
+
|
|
107
|
+
```yaml
|
|
108
|
+
---
|
|
109
|
+
scope: GENERAL
|
|
110
|
+
name: business-analysis-report
|
|
111
|
+
description: Analyze business data with the data-query workflow and generate stakeholder-facing reports with markdown and ECharts.
|
|
112
|
+
introduction:
|
|
113
|
+
title: '{{t("ai.skills.businessAnalysisReport.title", { ns: "@nocobase/plugin-ai" })}}'
|
|
114
|
+
about: '{{t("ai.skills.businessAnalysisReport.about", { ns: "@nocobase/plugin-ai" })}}'
|
|
115
|
+
tools:
|
|
116
|
+
- getSkill
|
|
117
|
+
- businessReportGenerator
|
|
118
|
+
---
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Instead of merely saying “generate a business report,” the content goes on to require the following:
|
|
122
|
+
|
|
123
|
+
- Understand the decision objective, audience, time range, and metrics first
|
|
124
|
+
- When business data is involved, the first ToolCall must load the `data-query` Skill
|
|
125
|
+
- Never guess tables, relationship paths, or query results
|
|
126
|
+
- Call `businessReportGenerator` only after the data is ready
|
|
127
|
+
- Generate charts and the Markdown report in the same ToolCall
|
|
128
|
+
- Determine success from the returned `status`, `chartCount`, `errors`, and `warnings`
|
|
129
|
+
- Retry a chart failure only once, then fall back to a Markdown-only report
|
|
130
|
+
|
|
131
|
+
These rules are the main value of a Skill—they narrow “what the model can do” into a repeatable, verifiable process.
|
|
132
|
+
|
|
133
|
+
## Related links
|
|
134
|
+
|
|
135
|
+
- [AI employee plugin development](./index.md) — Understand where Skills fit into AI employee extensions
|
|
136
|
+
- [Define a server-side Tool](./define-tool.md) — Define a Tool that a Skill can call
|
|
137
|
+
- [Define a built-in AI employee](./define-ai-employee.md) — Bind a Skill to a fixed employee
|
|
138
|
+
- [Complete example: Create a built-in AI employee](./complete-example.md) — See a complete Skill and Tool binding example
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Define a Server-side Tool"
|
|
3
|
+
description: "Explains defineTools, scope, schema, invoke, permissions, and directory registration for NocoBase AI employee server-side Tools."
|
|
4
|
+
keywords: "NocoBase,AI employee Tool,defineTools,ToolsOptions,Zod,invoke"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Define a Server-side Tool
|
|
8
|
+
|
|
9
|
+
## Minimal Tool structure
|
|
10
|
+
|
|
11
|
+
Define a server-side Tool with `defineTools()` from `@nocobase/ai`. The following Tool accepts a name and returns a greeting:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import type { Context } from '@nocobase/actions';
|
|
15
|
+
import { defineTools } from '@nocobase/ai';
|
|
16
|
+
import { z } from 'zod';
|
|
17
|
+
|
|
18
|
+
export default defineTools({
|
|
19
|
+
scope: 'SPECIFIED',
|
|
20
|
+
defaultPermission: 'ALLOW',
|
|
21
|
+
introduction: {
|
|
22
|
+
title: '{{t("ai.tools.greetDeveloper.title", { ns: "@nocobase/plugin-developer-helper" })}}',
|
|
23
|
+
about: '{{t("ai.tools.greetDeveloper.about", { ns: "@nocobase/plugin-developer-helper" })}}',
|
|
24
|
+
},
|
|
25
|
+
definition: {
|
|
26
|
+
name: 'greetDeveloper',
|
|
27
|
+
description: 'Generate a short greeting for the developer named by the user.',
|
|
28
|
+
schema: z.object({
|
|
29
|
+
name: z.string().min(1).describe('The developer name to greet.'),
|
|
30
|
+
}),
|
|
31
|
+
},
|
|
32
|
+
invoke: async (_ctx: Context, args: { name: string }) => {
|
|
33
|
+
return {
|
|
34
|
+
status: 'success',
|
|
35
|
+
content: `Hello ${args.name}, welcome to NocoBase plugin development!`,
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
If the file path is `src/ai/tools/greetDeveloper.ts`, the loader uses the filename `greetDeveloper` as the final Tool name. Even if `definition.name` contains another value, registration overrides it with the filename.
|
|
42
|
+
|
|
43
|
+
Therefore, keep the filename, `definition.name`, the name referenced by the Skill, and the name registered on the frontend consistent by default.
|
|
44
|
+
|
|
45
|
+
## Tool options
|
|
46
|
+
|
|
47
|
+
The main `defineTools()` options are:
|
|
48
|
+
|
|
49
|
+
| Option | Purpose | Default |
|
|
50
|
+
| --- | --- | --- |
|
|
51
|
+
| `scope` | Determines the Tool's availability scope | Required |
|
|
52
|
+
| `execution` | Specifies whether the logic runs on the `backend` or `frontend` | `backend` |
|
|
53
|
+
| `defaultPermission` | Allows the Tool directly or asks for confirmation before a call | `ASK` |
|
|
54
|
+
| `silence` | Hides the Tool call indicator in the conversation | `false` |
|
|
55
|
+
| `introduction` | Title and description displayed in the management interface | Uses the Tool name |
|
|
56
|
+
| `definition` | Provides the name, description, and parameter schema to the model | Required |
|
|
57
|
+
| `invoke` | Actual execution logic of the Tool | Required |
|
|
58
|
+
|
|
59
|
+
The selected `scope` directly affects how the Tool enters an AI employee's context:
|
|
60
|
+
|
|
61
|
+
| `scope` | Usage |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| `GENERAL` | Shared by all AI employees, usually for general foundational capabilities |
|
|
64
|
+
| `SPECIFIED` | Available only to a Skill or AI employee that binds the Tool |
|
|
65
|
+
| `CUSTOM` | Administrators can add it manually in AI employee configuration and set it to “Ask” or “Allow” |
|
|
66
|
+
|
|
67
|
+
Use `SPECIFIED` by default. Use `GENERAL` only when every AI employee definitely needs the capability. Use `CUSTOM` when administrators should select it per employee.
|
|
68
|
+
|
|
69
|
+
## `definition` is written for the model
|
|
70
|
+
|
|
71
|
+
`definition.description` and `definition.schema` affect whether the model selects the Tool and how it constructs arguments. The description should explain three things:
|
|
72
|
+
|
|
73
|
+
- When to call the Tool
|
|
74
|
+
- What each argument represents
|
|
75
|
+
- Which tasks the Tool should not handle
|
|
76
|
+
|
|
77
|
+
Zod is recommended for the parameter schema:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
schema: z.object({
|
|
81
|
+
query: z.string().describe('A specific search query.'),
|
|
82
|
+
limit: z.number().int().min(1).max(20).default(5).describe('Maximum number of records to return.'),
|
|
83
|
+
})
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The Tool name must also remain stable. Skills, AI employee configurations, frontend cards, and saved chat messages all locate it by name.
|
|
87
|
+
|
|
88
|
+
## What `invoke()` receives
|
|
89
|
+
|
|
90
|
+
A server-side `invoke()` receives three arguments:
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
invoke: async (ctx, args, runtime) => {
|
|
94
|
+
// ctx:当前 NocoBase action Context
|
|
95
|
+
// args:模型根据 schema 生成的参数
|
|
96
|
+
// runtime.toolCallId:当前 ToolCall ID
|
|
97
|
+
// runtime.writer(chunk):流式写出中间结果
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Through `ctx`, you can access the current application, database, authentication information, and action arguments. For example:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
const repository = ctx.app.db.getRepository('posts');
|
|
105
|
+
const currentUser = ctx.auth?.user;
|
|
106
|
+
const values = ctx.action?.params?.values;
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
A Tool should return a structure that clearly indicates success or failure. Built-in Tools commonly use this shape:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
return {
|
|
113
|
+
status: 'success',
|
|
114
|
+
content: result,
|
|
115
|
+
};
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
For expected business failures, return a clear status and reason instead of making the model guess whether the operation succeeded.
|
|
119
|
+
|
|
120
|
+
## Directory-based Tools
|
|
121
|
+
|
|
122
|
+
A Tool can use a directory instead of a single file:
|
|
123
|
+
|
|
124
|
+
```text
|
|
125
|
+
src/ai/tools/documentSearch/
|
|
126
|
+
├── index.ts
|
|
127
|
+
└── description.md
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`index.ts` exports the result of `defineTools()` by default. When `description.md` exists, its entire content overrides `definition.description`, making it suitable for longer Tool instructions.
|
|
131
|
+
|
|
132
|
+
The directory name `documentSearch` becomes the final registered name.
|
|
133
|
+
|
|
134
|
+
## Built-in Tool example: `subAgentWebSearch`
|
|
135
|
+
|
|
136
|
+
`packages/plugins/@nocobase/plugin-ai/src/ai/tools/subAgentWebSearch.ts` demonstrates a complete server-side Tool:
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
export default defineTools({
|
|
140
|
+
scope: 'SPECIFIED',
|
|
141
|
+
defaultPermission: 'ALLOW',
|
|
142
|
+
introduction: {
|
|
143
|
+
title: '{{t("Web search")}}',
|
|
144
|
+
about: '{{t("Use web search to quickly find up-to-date information from the internet.")}}',
|
|
145
|
+
},
|
|
146
|
+
definition: {
|
|
147
|
+
name: 'subAgentWebSearch',
|
|
148
|
+
description: 'Search the web for current information...',
|
|
149
|
+
schema: z.object({
|
|
150
|
+
query: z.array(z.string()),
|
|
151
|
+
}),
|
|
152
|
+
},
|
|
153
|
+
invoke: async (ctx, args) => {
|
|
154
|
+
// 获取 AI 插件和当前会话使用的模型配置。
|
|
155
|
+
const pluginAI = ctx.app.pm.get('ai') as PluginAIServer;
|
|
156
|
+
const { model } = ctx.action?.params?.values ?? {};
|
|
157
|
+
const { provider } = await pluginAI.aiManager.getLLMService({
|
|
158
|
+
...model,
|
|
159
|
+
webSearch: true,
|
|
160
|
+
reasoning: { mode: 'off' },
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// 独立查询并行执行,最后统一返回。
|
|
164
|
+
const result = await Promise.all(
|
|
165
|
+
args.query.map(async (query) => {
|
|
166
|
+
const content = await provider.invoke(/* messages */);
|
|
167
|
+
return { query, result: content.text };
|
|
168
|
+
}),
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
return { status: 'success', content: result };
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
This implementation demonstrates several reusable practices:
|
|
177
|
+
|
|
178
|
+
- Use `SPECIFIED` to limit the Tool to designated employees or Skills
|
|
179
|
+
- Use Zod to constrain model-generated arguments
|
|
180
|
+
- Read the current AI conversation configuration from `ctx.action.params.values`
|
|
181
|
+
- Put multiple independent queries into one ToolCall and run them concurrently with `Promise.all()`
|
|
182
|
+
- Return structured results with clear provenance for the higher-level model to process
|
|
183
|
+
|
|
184
|
+
## Related links
|
|
185
|
+
|
|
186
|
+
- [AI employee plugin development](./index.md) — Choose which capability layer to extend
|
|
187
|
+
- [Define a Skill](./define-skill.md) — Use a Skill to organize the call flow for multiple Tools
|
|
188
|
+
- [Complete example: Create a built-in AI employee](./complete-example.md) — See a runnable Tool example
|
|
189
|
+
- [Add frontend interaction to a Tool](./frontend-tool-ui.md) — Add confirmation and selection UI to a ToolCall
|