@nocobase/plugin-ai 2.2.0-alpha.6 → 2.2.0-alpha.8
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/file-manager/storage/local.md +3 -1
- package/dist/ai/docs/nocobase/multi-app/multi-app-vs-multi-portal-vs-multi-space.md +159 -0
- package/dist/ai/docs/nocobase/multi-app/multi-portal/index.md +195 -0
- package/dist/ai/docs/nocobase/security/guide.md +23 -0
- package/dist/ai/tools/formFiller.js +4 -3
- package/dist/ai/tools/subAgentWebSearch.js +20 -15
- package/dist/client/372.40eb52905e3f3049.js +10 -0
- package/dist/client/index.js +3 -3
- package/dist/client-v2/372.8cc3fde09c9bec77.js +10 -0
- package/dist/client-v2/ai-employees/tools/data-modeling/useFieldInterfaceOptions.d.ts +1 -0
- package/dist/client-v2/index.js +2 -2
- package/dist/client-v2/llm-providers/forms.d.ts +2 -0
- package/dist/client-v2/llm-providers/index.d.ts +1 -0
- package/dist/client-v2/pages/EmployeesPage.d.ts +9 -0
- package/dist/externalVersion.js +15 -15
- package/dist/locale/en-US.json +6 -0
- package/dist/locale/zh-CN.json +6 -0
- 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/server/ai-employees/ai-employee.js +2 -1
- package/dist/server/ai-employees/prompts.d.ts +2 -1
- package/dist/server/ai-employees/prompts.js +8 -2
- package/dist/server/ai-employees/tool-call-sanitizer.d.ts +1 -0
- package/dist/server/ai-employees/tool-call-sanitizer.js +2 -1
- package/dist/server/ai-employees/utils.js +11 -5
- package/dist/server/collections/ai-usage-events.d.ts +10 -0
- package/dist/server/collections/ai-usage-events.js +183 -0
- package/dist/server/llm-providers/dashscope.d.ts +2 -1
- package/dist/server/llm-providers/dashscope.js +16 -1
- package/dist/server/llm-providers/deepseek.d.ts +2 -1
- package/dist/server/llm-providers/deepseek.js +33 -2
- package/dist/server/llm-providers/kimi/provider.d.ts +2 -1
- package/dist/server/llm-providers/kimi/provider.js +22 -2
- package/dist/server/llm-providers/mistral.d.ts +36 -2
- package/dist/server/llm-providers/mistral.js +62 -2
- package/dist/server/llm-providers/openai/completions.d.ts +2 -1
- package/dist/server/llm-providers/openai/completions.js +17 -1
- package/dist/server/llm-providers/openai/responses.d.ts +2 -1
- package/dist/server/llm-providers/openai/responses.js +17 -1
- package/dist/server/llm-providers/orcarouter.d.ts +35 -0
- package/dist/server/llm-providers/orcarouter.js +155 -0
- package/dist/server/llm-providers/provider.d.ts +7 -0
- package/dist/server/llm-providers/provider.js +7 -1
- package/dist/server/manager/ai-chat-conversation.js +2 -0
- package/dist/server/manager/ai-context-datasource-manager.js +34 -7
- package/dist/server/manager/ai-manager.d.ts +2 -1
- package/dist/server/manager/ai-manager.js +4 -1
- package/dist/server/manager/ai-usage-events.d.ts +49 -0
- package/dist/server/manager/ai-usage-events.js +195 -0
- package/dist/server/plugin.js +2 -0
- package/package.json +2 -2
- package/dist/client/372.da38fe350bf841f4.js +0 -10
- package/dist/client-v2/372.d76ea1ceed2be2a4.js +0 -10
|
@@ -9,6 +9,8 @@ Local Storage does not support private access. After a file is uploaded, NocoBas
|
|
|
9
9
|
|
|
10
10
|
If you need to store contracts, identity documents, internal materials, or other files that should not be public, use [S3 Pro](./s3-pro). If historical files already exist, see [Migrate to S3 Pro](./migrate-to-s3-pro.md).
|
|
11
11
|
|
|
12
|
+
If you are not using Docker or the official nginx configuration and access local uploaded files through a custom proxy, make sure the `/storage/uploads/` path sets `X-Content-Type-Options: nosniff` and returns active content files such as `html`, `svg`, `xhtml`, and `pdf` as attachments. For details, see [Security guide: File storage](../../security/guide.md#file-storage).
|
|
13
|
+
|
|
12
14
|
:::
|
|
13
15
|
|
|
14
16
|
## Configuration Parameters
|
|
@@ -26,4 +28,4 @@ This section only introduces parameters specific to the local storage engine. Fo
|
|
|
26
28
|
Represents both the relative path for file storage on the server and the URL access path. For example, "`user/avatar`" (without leading or trailing slashes) represents:
|
|
27
29
|
|
|
28
30
|
1. The relative path on the server where uploaded files are stored: `/path/to/nocobase-app/storage/uploads/user/avatar`.
|
|
29
|
-
2. The URL prefix for accessing the files: `http://localhost:13000/storage/uploads/user/avatar`.
|
|
31
|
+
2. The URL prefix for accessing the files: `http://localhost:13000/storage/uploads/user/avatar`.
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# Multi-portal, Multi-app, and Multi-space
|
|
2
|
+
|
|
3
|
+
NocoBase provides three capabilities: Multi-portal, Multi-app, and Multi-space.
|
|
4
|
+
|
|
5
|
+
They solve problems at different levels. They can be used independently or together.
|
|
6
|
+
|
|
7
|
+
## Key differences
|
|
8
|
+
|
|
9
|
+
| Capability | Multi-portal | Multi-app | Multi-space |
|
|
10
|
+
|------|------|------|------|
|
|
11
|
+
| What problem it solves | Provides multiple access entries | Splits business into multiple systems | Isolates business data |
|
|
12
|
+
| Core focus | Where users enter | How the system is divided | Who the data belongs to |
|
|
13
|
+
| Data | Shared | Independent by default | Isolated |
|
|
14
|
+
| Pages and menus | Independent | Independent | Shared |
|
|
15
|
+
| Plugin configuration | Shared | Independent | Shared |
|
|
16
|
+
| User system | Shared | Can be shared through SSO | Shared |
|
|
17
|
+
| Typical scenarios | Different roles need different entries | Different businesses need independent management | Multiple organizations, stores, or tenants |
|
|
18
|
+
| Can be combined | Yes | Yes | Yes |
|
|
19
|
+
|
|
20
|
+
## Multi-portal
|
|
21
|
+
|
|
22
|
+
Multi-portal provides multiple access entries within the same application.
|
|
23
|
+
|
|
24
|
+
For example:
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
ERP App
|
|
28
|
+
|
|
29
|
+
├─ Admin Portal (/v/admin)
|
|
30
|
+
├─ Store Portal (/v/store)
|
|
31
|
+
├─ Distributor Portal (/v/dealer)
|
|
32
|
+
└─ Mobile Portal (/v/mobile)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Features:
|
|
36
|
+
|
|
37
|
+
- Uses the same application
|
|
38
|
+
- Shares the same data
|
|
39
|
+
- Shares plugin configuration
|
|
40
|
+
- Pages and menus can be configured independently
|
|
41
|
+
|
|
42
|
+
Suitable for scenarios where different roles need different access entries, such as:
|
|
43
|
+
|
|
44
|
+
- Administrators
|
|
45
|
+
- Employees
|
|
46
|
+
- Customers
|
|
47
|
+
- Distributors
|
|
48
|
+
|
|
49
|
+
## Multi-app
|
|
50
|
+
|
|
51
|
+
Multi-app splits business into multiple independent applications.
|
|
52
|
+
|
|
53
|
+
For example:
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
Group System
|
|
57
|
+
|
|
58
|
+
├─ CRM
|
|
59
|
+
├─ ERP
|
|
60
|
+
├─ OA
|
|
61
|
+
└─ Analytics
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Features:
|
|
65
|
+
|
|
66
|
+
- Each app is managed independently
|
|
67
|
+
- Independent plugin configuration
|
|
68
|
+
- Independent database connection
|
|
69
|
+
- Independent upgrade and maintenance
|
|
70
|
+
|
|
71
|
+
Suitable for:
|
|
72
|
+
|
|
73
|
+
- Splitting large business systems
|
|
74
|
+
- Multi-team collaborative development
|
|
75
|
+
- Batch creation of apps for SaaS platforms
|
|
76
|
+
- Independent apps for different customers
|
|
77
|
+
|
|
78
|
+
## Multi-space
|
|
79
|
+
|
|
80
|
+
Multi-space isolates business data within the same application.
|
|
81
|
+
|
|
82
|
+
For example:
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
Store Management App
|
|
86
|
+
|
|
87
|
+
Spaces
|
|
88
|
+
├─ Beijing Store
|
|
89
|
+
├─ Shanghai Store
|
|
90
|
+
└─ Shenzhen Store
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Features:
|
|
94
|
+
|
|
95
|
+
- Shared pages
|
|
96
|
+
- Shared menus
|
|
97
|
+
- Shared workflows
|
|
98
|
+
- Shared configuration
|
|
99
|
+
- Isolated data
|
|
100
|
+
|
|
101
|
+
For tables that have a space field enabled, the system automatically filters data according to the current space.
|
|
102
|
+
|
|
103
|
+
From the user's perspective:
|
|
104
|
+
|
|
105
|
+
- The Beijing store can only see Beijing store data
|
|
106
|
+
- The Shanghai store can only see Shanghai store data
|
|
107
|
+
- The Shenzhen store can only see Shenzhen store data
|
|
108
|
+
|
|
109
|
+
But all stores still use the same system.
|
|
110
|
+
|
|
111
|
+
## Relationship among the three
|
|
112
|
+
|
|
113
|
+
These three capabilities do not conflict. They work on different dimensions.
|
|
114
|
+
|
|
115
|
+
They can be used together:
|
|
116
|
+
|
|
117
|
+
```text
|
|
118
|
+
Group System
|
|
119
|
+
|
|
120
|
+
CRM App
|
|
121
|
+
├─ Admin Portal
|
|
122
|
+
├─ Sales Portal
|
|
123
|
+
└─ Customer Portal
|
|
124
|
+
|
|
125
|
+
Spaces
|
|
126
|
+
├─ Beijing Branch
|
|
127
|
+
├─ Shanghai Branch
|
|
128
|
+
└─ Shenzhen Branch
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Conceptually:
|
|
132
|
+
|
|
133
|
+
```text
|
|
134
|
+
Portal
|
|
135
|
+
↓
|
|
136
|
+
Where users enter the system
|
|
137
|
+
|
|
138
|
+
App
|
|
139
|
+
↓
|
|
140
|
+
How the system is divided
|
|
141
|
+
|
|
142
|
+
Space
|
|
143
|
+
↓
|
|
144
|
+
Who the data belongs to
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## How to choose
|
|
148
|
+
|
|
149
|
+
If you only want to provide different entries for different roles, choose **Multi-portal**.
|
|
150
|
+
|
|
151
|
+
If you want to split business into multiple independent systems, choose **Multi-app**.
|
|
152
|
+
|
|
153
|
+
If you want to isolate data for different organizations or tenants within the same system, choose **Multi-space**.
|
|
154
|
+
|
|
155
|
+
In real projects, these three capabilities are usually combined rather than used as substitutes for one another.
|
|
156
|
+
|
|
157
|
+
In one sentence:
|
|
158
|
+
|
|
159
|
+
> Multi-portal solves entry points, Multi-app solves system splitting, and Multi-space solves data isolation.
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Multi-portal"
|
|
3
|
+
description: "Learn the concept, use cases, configuration, and relationship between Multi-portal, Multi-app, and Multi-space in NocoBase."
|
|
4
|
+
keywords: "workspace, portal, multi-portal, NocoBase"
|
|
5
|
+
pkg: "@nocobase/plugin-multi-portal"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Multi-portal
|
|
9
|
+
|
|
10
|
+
## What is a portal
|
|
11
|
+
|
|
12
|
+
A portal is used to provide multiple access entries within the same application.
|
|
13
|
+
|
|
14
|
+
Each portal can have its own:
|
|
15
|
+
|
|
16
|
+
- Pages
|
|
17
|
+
- Menus
|
|
18
|
+
- Navigation structure
|
|
19
|
+
- Layout
|
|
20
|
+
- Permission settings
|
|
21
|
+
|
|
22
|
+
The Multi-portal plugin provides the following capabilities:
|
|
23
|
+
|
|
24
|
+
- Portal management
|
|
25
|
+
- Portal switching
|
|
26
|
+
- Portal permission control
|
|
27
|
+
|
|
28
|
+
With these capabilities, you can provide different experiences for different roles while sharing the same data and business capabilities.
|
|
29
|
+
|
|
30
|
+
## Why use portals
|
|
31
|
+
|
|
32
|
+
In real business scenarios, different roles often need different interfaces.
|
|
33
|
+
|
|
34
|
+
For example, in a retail management system:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
Retail Management System
|
|
38
|
+
|
|
39
|
+
├─ Headquarters Portal
|
|
40
|
+
├─ Store Portal
|
|
41
|
+
├─ Distributor Portal
|
|
42
|
+
└─ Mobile Portal
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Headquarters staff focus on:
|
|
46
|
+
|
|
47
|
+
- Product management
|
|
48
|
+
- Inventory management
|
|
49
|
+
- Data analysis
|
|
50
|
+
|
|
51
|
+
Store staff focus on:
|
|
52
|
+
|
|
53
|
+
- Cashiering
|
|
54
|
+
- Stocktaking
|
|
55
|
+
- Order processing
|
|
56
|
+
|
|
57
|
+
Distributors focus on:
|
|
58
|
+
|
|
59
|
+
- Purchasing
|
|
60
|
+
- Reconciliation
|
|
61
|
+
- Shipment status
|
|
62
|
+
|
|
63
|
+
Although everyone uses the same system, different roles do not need to see the same menus and pages.
|
|
64
|
+
|
|
65
|
+
That is exactly the problem portals solve.
|
|
66
|
+
|
|
67
|
+
## Relationship between portals and menus
|
|
68
|
+
|
|
69
|
+
Each portal has its own menu tree.
|
|
70
|
+
|
|
71
|
+
Menus in different portals do not affect each other.
|
|
72
|
+
|
|
73
|
+
For example:
|
|
74
|
+
|
|
75
|
+
```text
|
|
76
|
+
Headquarters Portal
|
|
77
|
+
├─ Product Management
|
|
78
|
+
├─ Supply Chain Management
|
|
79
|
+
└─ Data Analysis
|
|
80
|
+
|
|
81
|
+
Store Portal
|
|
82
|
+
├─ Cashiering
|
|
83
|
+
├─ Order Management
|
|
84
|
+
└─ Stocktaking
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Relationship between portals and pages
|
|
88
|
+
|
|
89
|
+
Pages belong to their respective portals.
|
|
90
|
+
|
|
91
|
+
The same page can also be shown only in specific portals.
|
|
92
|
+
|
|
93
|
+
This makes it possible to design completely different workflows for different roles.
|
|
94
|
+
|
|
95
|
+
## Relationship between portals and permissions
|
|
96
|
+
|
|
97
|
+
Portals themselves can be configured with access permissions.
|
|
98
|
+
|
|
99
|
+
Only authorized users can access the corresponding portal.
|
|
100
|
+
|
|
101
|
+
Unauthorized portals:
|
|
102
|
+
|
|
103
|
+
- Do not appear in the switcher list
|
|
104
|
+
- Cannot be accessed directly
|
|
105
|
+
|
|
106
|
+
## Portal management
|
|
107
|
+
|
|
108
|
+
After enabling the Multi-portal plugin, the system provides two built-in portals by default:
|
|
109
|
+
|
|
110
|
+
| Portal | Path | Purpose |
|
|
111
|
+
|----------|----------|----------|
|
|
112
|
+
| Desktop | `/v/admin` | Desktop entry |
|
|
113
|
+
| Mobile | `/v/mobile` | Mobile entry |
|
|
114
|
+
|
|
115
|
+
### Built-in portals
|
|
116
|
+
|
|
117
|
+

|
|
118
|
+
|
|
119
|
+
### Desktop portal
|
|
120
|
+
|
|
121
|
+
Access path:
|
|
122
|
+
|
|
123
|
+
```text
|
|
124
|
+
/v/admin
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+

|
|
128
|
+
|
|
129
|
+
### Mobile portal
|
|
130
|
+
|
|
131
|
+
Access path:
|
|
132
|
+
|
|
133
|
+
```text
|
|
134
|
+
/v/mobile
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+

|
|
138
|
+
|
|
139
|
+
## Create a portal
|
|
140
|
+
|
|
141
|
+
In addition to the built-in portals, you can create more portals based on business needs.
|
|
142
|
+
|
|
143
|
+
For example:
|
|
144
|
+
|
|
145
|
+
- Store portal
|
|
146
|
+
- Distributor portal
|
|
147
|
+
- Customer service portal
|
|
148
|
+
- Data analysis portal
|
|
149
|
+
|
|
150
|
+
After creation, you can configure:
|
|
151
|
+
|
|
152
|
+
- Pages
|
|
153
|
+
- Menus
|
|
154
|
+
- Permissions
|
|
155
|
+
- Navigation
|
|
156
|
+
|
|
157
|
+

|
|
158
|
+
|
|
159
|
+
## Switch portals
|
|
160
|
+
|
|
161
|
+
Users can quickly switch between portals through the portal switcher.
|
|
162
|
+
|
|
163
|
+
### Switch portals within a single app
|
|
164
|
+
|
|
165
|
+
Add it to the portal switcher panel in the upper-left corner
|
|
166
|
+
|
|
167
|
+

|
|
168
|
+
|
|
169
|
+
Add it to the action panel block
|
|
170
|
+
|
|
171
|
+

|
|
172
|
+
|
|
173
|
+
### Switch portals across apps
|
|
174
|
+
|
|
175
|
+
After enabling Multi-app and configuring SSO, users can also switch between portals across different apps through the portal switcher.
|
|
176
|
+
|
|
177
|
+
Add it to the portal switcher panel in the upper-left corner
|
|
178
|
+
|
|
179
|
+

|
|
180
|
+
|
|
181
|
+
Add it to the action panel block
|
|
182
|
+
|
|
183
|
+

|
|
184
|
+
|
|
185
|
+
## Portal permissions
|
|
186
|
+
|
|
187
|
+
You can control which portals a user can access through role permissions.
|
|
188
|
+
|
|
189
|
+
Unauthorized portals do not appear in the portal switcher list, and users cannot access those entries directly.
|
|
190
|
+
|
|
191
|
+

|
|
192
|
+
|
|
193
|
+
## Related links
|
|
194
|
+
|
|
195
|
+
For the differences and combination patterns among Multi-portal, Multi-app, and Multi-space, see: [Multi-portal, Multi-app, and Multi-space](../multi-app-vs-multi-portal-vs-multi-space.md).
|
|
@@ -215,6 +215,29 @@ If you need to store sensitive files, it is recommended to use a cloud storage s
|
|
|
215
215
|
|
|
216
216
|
For local storage or other public storage that can be accessed directly through same-origin application URLs, you should also pay extra attention to the risks introduced by active content files. Files such as `html`, `xhtml`, and `svg` may be parsed and executed directly by the browser. If an attacker can upload such a file and trick a user into opening it, the attacker may use your trusted application domain to host a malicious page or script.
|
|
217
217
|
|
|
218
|
+
NocoBase upload validation does not trust the `Content-Type` sent by the request. It prefers the MIME type detected on the server side. A file extension only represents the filename and should not be treated as the authoritative file content type. Therefore, when serving public uploaded files, you also need to make sure the file access path has proper security response headers.
|
|
219
|
+
|
|
220
|
+
If you deploy with Docker or use the nginx configuration generated by NocoBase, the upload directory already includes this protection: all uploaded files return `X-Content-Type-Options: nosniff`, and active content files such as `html`, `xhtml`, `svg`, `svgz`, and `pdf` are returned as downloads through `Content-Disposition: attachment`.
|
|
221
|
+
|
|
222
|
+
If you use a custom proxy, CDN, object storage, or expose the local upload directory directly, make sure these rules are not bypassed. You can use the following nginx configuration as a reference:
|
|
223
|
+
|
|
224
|
+
```nginx
|
|
225
|
+
location ~* ^/storage/uploads/(.*\.(?:htm|html|svg|svgz|xhtml|pdf))$ {
|
|
226
|
+
alias /path/to/nocobase/storage/uploads/$1;
|
|
227
|
+
add_header Content-Disposition "attachment" always;
|
|
228
|
+
add_header X-Content-Type-Options "nosniff" always;
|
|
229
|
+
autoindex off;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
location /storage/uploads/ {
|
|
233
|
+
alias /path/to/nocobase/storage/uploads/;
|
|
234
|
+
add_header X-Content-Type-Options "nosniff" always;
|
|
235
|
+
autoindex off;
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
If your NocoBase app uses `APP_PUBLIC_PATH`, replace `/storage/uploads/` with the actual access prefix, such as `/nocobase/storage/uploads/`.
|
|
240
|
+
|
|
218
241
|
In most cases, we recommend that administrators:
|
|
219
242
|
|
|
220
243
|
- Prefer private storage, signed URLs, or a separate file domain, so that user-uploaded files are not served directly from the same origin as the main application.
|
|
@@ -48,16 +48,17 @@ var formFiller_default = (0, import_ai.defineTools)({
|
|
|
48
48
|
execution: "frontend",
|
|
49
49
|
introduction: {
|
|
50
50
|
title: `{{t("Form filler", { ns: "${import_package.default.name}" })}}`,
|
|
51
|
-
about: `{{t("Fill
|
|
51
|
+
about: `{{t("Fill form fields with the given content. This tool only writes values into the form UI; it does not submit or save the form.", { ns: "${import_package.default.name}" })}}`
|
|
52
52
|
},
|
|
53
53
|
definition: {
|
|
54
54
|
name: "formFiller",
|
|
55
|
-
description: "Fill
|
|
55
|
+
description: "Fill form fields with the given content. This tool only writes values into the form UI; it does not submit, save, create, or update records. After using it, tell the user to review the filled values and manually submit the form.",
|
|
56
56
|
schema: import_zod.z.object({
|
|
57
57
|
form: import_zod.z.string().describe("The UI Schema ID of the target form to be filled."),
|
|
58
58
|
data: import_zod.z.object({}).catchall(import_zod.z.any()).describe(
|
|
59
59
|
`Structured key-value pairs matching the form's JSON Schema,
|
|
60
60
|
to be assigned to form.values.
|
|
61
|
+
This only populates fields in the form UI and does not submit, save, create, or update records.
|
|
61
62
|
Example: { "username": "alice", "email": "alice@example.com", "age": 30 }`
|
|
62
63
|
)
|
|
63
64
|
})
|
|
@@ -65,7 +66,7 @@ var formFiller_default = (0, import_ai.defineTools)({
|
|
|
65
66
|
invoke: async () => {
|
|
66
67
|
return {
|
|
67
68
|
status: "success",
|
|
68
|
-
content: "I have filled the form with the provided data."
|
|
69
|
+
content: "I have filled the form with the provided data. Please review the values and manually submit the form to save the data."
|
|
69
70
|
};
|
|
70
71
|
}
|
|
71
72
|
});
|
|
@@ -40,9 +40,12 @@ var subAgentWebSearch_default = (0, import_ai.defineTools)({
|
|
|
40
40
|
},
|
|
41
41
|
definition: {
|
|
42
42
|
name: "subAgentWebSearch",
|
|
43
|
-
description: "
|
|
43
|
+
description: "Search the web for current information. Put all independent search queries needed for this turn into one call so they can run in parallel. Do not call this tool repeatedly with similar queries unless the previous results are clearly insufficient for a critical missing fact.",
|
|
44
44
|
schema: import_zod.z.object({
|
|
45
|
-
query: import_zod.z.array(
|
|
45
|
+
query: import_zod.z.array(
|
|
46
|
+
import_zod.z.string(),
|
|
47
|
+
"A list of clear, specific, non-overlapping web search queries. Include all independent queries needed for this answer in a single tool call so they can run in parallel."
|
|
48
|
+
)
|
|
46
49
|
})
|
|
47
50
|
},
|
|
48
51
|
invoke: async (ctx, args, id) => {
|
|
@@ -51,7 +54,8 @@ var subAgentWebSearch_default = (0, import_ai.defineTools)({
|
|
|
51
54
|
const { model } = ((_b = (_a = ctx.action) == null ? void 0 : _a.params) == null ? void 0 : _b.values) ?? {};
|
|
52
55
|
const { provider } = await pluginAI.aiManager.getLLMService({
|
|
53
56
|
...model,
|
|
54
|
-
webSearch: true
|
|
57
|
+
webSearch: true,
|
|
58
|
+
reasoning: { mode: "off" }
|
|
55
59
|
});
|
|
56
60
|
if (!((_c = args.query) == null ? void 0 : _c.length)) {
|
|
57
61
|
return {
|
|
@@ -85,19 +89,20 @@ var subAgentWebSearch_default = (0, import_ai.defineTools)({
|
|
|
85
89
|
};
|
|
86
90
|
}
|
|
87
91
|
});
|
|
88
|
-
const WEB_SEARCH_SYSTEM_PROMPT = `You are a web search assistant.
|
|
92
|
+
const WEB_SEARCH_SYSTEM_PROMPT = `You are a web search retrieval assistant.
|
|
89
93
|
|
|
90
|
-
Your
|
|
94
|
+
Your output is for another AI model, not the final user-facing answer.
|
|
91
95
|
|
|
92
96
|
Requirements:
|
|
93
|
-
1.
|
|
94
|
-
2.
|
|
95
|
-
3.
|
|
96
|
-
4.
|
|
97
|
-
5.
|
|
98
|
-
6.
|
|
97
|
+
1. Retrieve current, relevant information for the query.
|
|
98
|
+
2. Return concise findings only. Do not write a polished final answer.
|
|
99
|
+
3. Include source title, publisher/site, URL, and publication or update date when available.
|
|
100
|
+
4. Prefer authoritative and recent sources.
|
|
101
|
+
5. Distinguish confirmed facts from uncertain or incomplete information.
|
|
102
|
+
6. Do not fabricate results, sources, dates, or URLs.
|
|
103
|
+
7. If results are weak, say exactly what is missing instead of broadening the search yourself.
|
|
99
104
|
|
|
100
|
-
Output
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
-
-
|
|
105
|
+
Output format:
|
|
106
|
+
- Findings: 3-6 concise bullet points.
|
|
107
|
+
- Sources: numbered list with title, site, URL, and date when available.
|
|
108
|
+
- Gaps: one short sentence if important information could not be verified.`;
|
|
@@ -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
|
+
|
|
10
|
+
"use strict";(self.webpackChunk_nocobase_plugin_ai=self.webpackChunk_nocobase_plugin_ai||[]).push([["372"],{1735:function(e,t,n){n.r(t),n.d(t,{EMPLOYEE_PROMPT_VARIABLE_NAMESPACES:function(){return B},EmployeesPage:function(){return ef},createAIEmployee:function(){return V},deleteAIEmployee:function(){return N},isKnowledgeBaseEnabled:function(){return q},listAIEmployees:function(){return G},listKnowledgeBases:function(){return X},moveAIEmployee:function(){return _},normalizeSkillSettings:function(){return en},updateAIEmployee:function(){return H},updateAIEmployeeEnabled:function(){return U}});var r=n(9155),l=n.n(r),a=n(2059),o=n(7375),i=n(5428),u=n(5477),s=n(3485),c=n(7694),m=n(9488),d=n(4196),f=n(3617),p=n(9312),y=n(8666);function b(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n<t;n++)r[n]=e[n];return r}function g(e){if(Array.isArray(e))return e}function h(e,t,n,r,l,a,o){try{var i=e[a](o),u=i.value}catch(e){n(e);return}i.done?t(u):Promise.resolve(u).then(r,l)}function v(e){return function(){var t=this,n=arguments;return new Promise(function(r,l){var a=e.apply(t,n);function o(e){h(a,r,l,o,i,"next",e)}function i(e){h(a,r,l,o,i,"throw",e)}o(void 0)})}}function E(e){if("u">typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}function S(){throw TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function k(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{},r=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(r=r.concat(Object.getOwnPropertySymbols(n).filter(function(e){return Object.getOwnPropertyDescriptor(n,e).enumerable}))),r.forEach(function(t){var r;r=n[t],t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r})}return e}function w(e,t){return t=null!=t?t:{},Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):(function(e){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t.push.apply(t,n)}return t})(Object(t)).forEach(function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}),e}function I(e,t){return g(e)||function(e,t){var n,r,l=null==e?null:"u">typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=l){var a=[],o=!0,i=!1;try{for(l=l.call(e);!(o=(n=l.next()).done)&&(a.push(n.value),!t||a.length!==t);o=!0);}catch(e){i=!0,r=e}finally{try{o||null==l.return||l.return()}finally{if(i)throw r}}return a}}(e,t)||C(e,t)||S()}function A(e){return function(e){if(Array.isArray(e))return b(e)}(e)||E(e)||C(e)||function(){throw TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function C(e,t){if(e){if("string"==typeof e)return b(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(n);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return b(e,t)}}function F(e,t){var n,r,l,a={label:0,sent:function(){if(1&l[0])throw l[1];return l[1]},trys:[],ops:[]},o=Object.create(("function"==typeof Iterator?Iterator:Object).prototype),i=Object.defineProperty;return i(o,"next",{value:u(0)}),i(o,"throw",{value:u(1)}),i(o,"return",{value:u(2)}),"function"==typeof Symbol&&i(o,Symbol.iterator,{value:function(){return this}}),o;function u(i){return function(u){var s=[i,u];if(n)throw TypeError("Generator is already executing.");for(;o&&(o=0,s[0]&&(a=0)),a;)try{if(n=1,r&&(l=2&s[0]?r.return:s[0]?r.throw||((l=r.return)&&l.call(r),0):r.next)&&!(l=l.call(r,s[1])).done)return l;switch(r=0,l&&(s=[2&s[0],l.value]),s[0]){case 0:case 1:l=s;break;case 4:return a.label++,{value:s[1],done:!1};case 5:a.label++,r=s[1],s=[0];continue;case 7:s=a.ops.pop(),a.trys.pop();continue;default:if(!(l=(l=a.trys).length>0&&l[l.length-1])&&(6===s[0]||2===s[0])){a=0;continue}if(3===s[0]&&(!l||s[1]>l[0]&&s[1]<l[3])){a.label=s[1];break}if(6===s[0]&&a.label<l[1]){a.label=l[1],l=s;break}if(l&&a.label<l[2]){a.label=l[2],a.ops.push(s);break}l[2]&&a.ops.pop(),a.trys.pop();continue}s=t.call(e,a)}catch(e){s=[6,e],r=0}finally{n=l=0}if(5&s[0])throw s[1];return{value:s[0]?s[1]:void 0,done:!0}}}}function x(){var e,t,n=(e=["\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n\n .ant-spin-nested-loading,\n .ant-spin-container,\n .ant-table,\n .ant-table-container {\n min-height: 0;\n flex: 1;\n display: flex;\n flex-direction: column;\n }\n\n .ant-table-content {\n flex: 1;\n min-height: 0;\n }\n\n .ant-table-body {\n flex: 1;\n min-height: 0;\n }\n\n .ant-table-thead > tr > th {\n white-space: nowrap;\n }\n\n .ant-pagination {\n flex: 0 0 auto;\n }\n"],t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}})));return x=function(){return n},n}var T=Object.keys(d.B)[0],O="sort",B=["user","roleName","locale","now","timestamp"],M=function(e){return"".concat(e,":")},P=(0,u.css)(x()),j=function(e){return null!==e&&(void 0===e?"undefined":e&&"u">typeof Symbol&&e.constructor===Symbol?"symbol":typeof e)=="object"&&!Array.isArray(e)},L=function(e){var t;if(j(e))return null==(t=e.data)?void 0:t.data},R=function(e){if(!j(e))return{};var t=e.data;return j(t)?t:{}},K=function(e){return j(e)&&"string"==typeof e.username},z=function(e){return j(e)&&"string"==typeof e.key&&"string"==typeof e.name},W=function(e,t,n,r){return v(function(){var l;return F(this,function(a){if("function"!=typeof(l=e.resource(t)[n]))throw Error("Missing resource action: ".concat(t,".").concat(n));return[2,l(r)]})})()},D=function(e,t){var n=k({},e);return t.edit&&("system"===e._aboutMode&&(n.about=null),delete n._aboutMode,delete n.enabled),n};function G(e,t){return v(function(){var n,r,l;return F(this,function(a){switch(a.label){case 0:return[4,W(e,"aiEmployees","list",{page:t.page,pageSize:t.pageSize,filter:{category:t.category},sort:[O]})];case 1:return r=L(n=a.sent()),l=R(n),[2,{data:Array.isArray(r)?r.filter(K):[],total:"number"==typeof l.count?l.count:void 0}]}})})()}function _(e,t,n){return v(function(){return F(this,function(r){switch(r.label){case 0:return[4,W(e,"aiEmployees","move",{sourceId:t,targetId:n,sortField:O})];case 1:return r.sent(),[2]}})})()}function V(e,t){return v(function(){return F(this,function(n){switch(n.label){case 0:return[4,W(e,"aiEmployees","create",{values:D(t,{edit:!1})})];case 1:return n.sent(),[2]}})})()}function H(e,t){return v(function(){return F(this,function(n){switch(n.label){case 0:if(!t.username)throw Error("Missing AI employee username.");return[4,W(e,"aiEmployees","update",{values:D(t,{edit:!0}),filterByTk:t.username})];case 1:return n.sent(),[2]}})})()}function N(e,t){return v(function(){return F(this,function(n){switch(n.label){case 0:return[4,W(e,"aiEmployees","destroy",{filterByTk:t})];case 1:return n.sent(),[2]}})})()}function U(e,t,n){return v(function(){return F(this,function(r){switch(r.label){case 0:return[4,W(e,"aiEmployees","update",{filterByTk:t,values:{enabled:n}})];case 1:return r.sent(),[2]}})})()}function q(e){return v(function(){var t;return F(this,function(n){switch(n.label){case 0:return[4,W(e,"aiSettings","isKnowledgeBaseEnabled")];case 1:return[2,j(t=L(n.sent()))&&!0===t.enabled]}})})()}function X(e){return v(function(){var t;return F(this,function(n){switch(n.label){case 0:return[4,W(e,"aiKnowledgeBase","list",{fields:["key","name"],filter:{enabled:!0}})];case 1:return[2,Array.isArray(t=L(n.sent()))?t.filter(z):[]]}})})()}var Y=function(e){var t=e.disabled,n=e.value,o=e.onChange,i=a.theme.useToken().token,u=n||T,s=(0,r.useMemo)(function(){return Object.keys(d.B).map(function(e){return{seed:e,uri:(0,d.H)(e)}})},[]);return l().createElement(l().Fragment,null,l().createElement("div",{style:{marginBottom:i.marginLG+i.margin}},l().createElement(a.Avatar,{size:2*i.controlHeightLG+i.paddingSM+2*i.lineWidth,src:(0,d.H)(u)})),t?null:l().createElement(a.List,{grid:{gutter:i.margin,column:10},dataSource:s,renderItem:function(e){return l().createElement(a.List.Item,null,l().createElement("button",{"aria-label":e.seed,type:"button",onClick:function(){return null==o?void 0:o(e.seed)},onKeyDown:function(t){("Enter"===t.key||" "===t.key)&&(t.preventDefault(),null==o||o(e.seed))},style:{background:"transparent",borderColor:u===e.seed?i.colorPrimary:"transparent",borderStyle:"solid",borderWidth:2*i.lineWidth,borderRadius:"50%",cursor:"pointer",display:"inline-flex",padding:0}},l().createElement(a.Avatar,{size:i.controlHeightLG+i.paddingSM+2*i.lineWidth,src:e.uri})))}}))},Q=function(e){var t=e.edit,n=e.builtIn,r=(0,m.kj)();return l().createElement(l().Fragment,null,l().createElement(a.Form.Item,{name:"username",label:M(r("Username")),rules:[{required:!0}],preserve:!0},l().createElement(a.Input,{disabled:t})),l().createElement(a.Form.Item,{name:"nickname",label:M(r("Nickname")),rules:[{required:!0}],preserve:!0},l().createElement(a.Input,{disabled:n})),l().createElement(a.Form.Item,{name:"position",label:M(r("Position")),extra:r("Position description"),preserve:!0},l().createElement(a.Input,{disabled:n,placeholder:r("Position placeholder")})),l().createElement(a.Form.Item,{name:"avatar",label:M(r("Avatar")),preserve:!0},l().createElement(Y,{disabled:n})),l().createElement(a.Form.Item,{name:"bio",label:M(r("Bio")),preserve:!0},l().createElement(a.Input.TextArea,{disabled:n,placeholder:r("Bio placeholder")})),l().createElement(a.Form.Item,{name:"greeting",label:M(r("Greeting message")),preserve:!0},l().createElement(a.Input.TextArea,{disabled:n,placeholder:r("Greeting message placeholder")})))},$=function(e){var t,n=e.builtIn,o=e.record,i=(0,m.kj)(),u=a.theme.useToken().token,c=a.Form.useFormInstance(),d=null!=(t=a.Form.useWatch("_aboutMode",c))?t:(null==o?void 0:o.about)?"custom":"system";return(0,r.useEffect)(function(){n&&!c.getFieldValue("_aboutMode")&&c.setFieldValue("_aboutMode",(null==o?void 0:o.about)?"custom":"system")},[n,c,null==o?void 0:o.about]),l().createElement(l().Fragment,null,l().createElement(a.Alert,{message:i("Role setting description"),type:"info",showIcon:!0}),n?l().createElement(a.Form.Item,{name:"_aboutMode",preserve:!0},l().createElement(a.Radio.Group,null,l().createElement(a.Radio,{value:"system"},i("System default")),l().createElement(a.Radio,{value:"custom"},i("Custom")))):null,n&&"system"===d?l().createElement(a.Typography.Paragraph,{copyable:!0,style:{backgroundColor:u.colorFillQuaternary,borderColor:u.colorBorder,borderRadius:u.borderRadius,borderStyle:"solid",borderWidth:u.lineWidth,margin:0,maxHeight:12*u.controlHeightLG,overflowY:"auto",paddingBlock:u.paddingSM,paddingInline:u.padding,whiteSpace:"pre-wrap",wordBreak:"break-word"}},(null==o?void 0:o.defaultPrompt)||""):l().createElement(a.Form.Item,{name:"about",label:M(i("Role setting")),preserve:!0},l().createElement(s.VariableTextArea,{namespaces:B,placeholder:i("Role setting placeholder"),rows:15})))},J=function(e){var t,n=g(t=e.split(":"))||E(t)||C(t)||S();return{llmService:n[0],model:n.slice(1).join(":")}},Z=function(e){return e.llmService&&e.model?"".concat(e.llmService,":").concat(e.model):void 0},ee=function(e){return j(e)?e:{}},et=function(e){return"string"==typeof e?{name:e,autoCall:!1}:j(e)&&"string"==typeof e.name?{name:e.name,autoCall:!0===e.autoCall}:void 0},en=function(e){return j(e)?{skills:Array.isArray(e.skills)?e.skills.filter(function(e){return"string"==typeof e}):[],tools:Array.isArray(e.tools)?e.tools.map(et).filter(function(e){return!!e}):[]}:{}},er=function(){var e=(0,f.M)(),t=I((0,r.useState)(!1),2),n=t[0],l=t[1];return(0,r.useEffect)(function(){var t=!1;return v(function(){return F(this,function(n){switch(n.label){case 0:l(!0),n.label=1;case 1:return n.trys.push([1,3,4,5]),[4,e.getLLMServices()];case 2:return n.sent(),[3,5];case 3:return console.error(n.sent()),[3,5];case 4:return t||l(!1),[7];case 5:return[2]}})})().catch(function(e){console.error(e)}),function(){t=!0}},[e]),{services:e.llmServices,loading:n||e.llmServicesLoading}},el=(0,c.observer)(function(){var e=(0,m.kj)(),t=a.Form.useFormInstance(),n=a.Form.useWatch("modelSettings",t),o=I((0,r.useState)(function(){return ee(t.getFieldValue("modelSettings"))}),2),i=o[0],u=o[1],s=er(),c=s.services,d=s.loading,f=!!i.enabled,p=(0,r.useMemo)(function(){var e=Array.isArray(i.models)?i.models:[];if(e.length)return e.map(Z).filter(function(e){return!!e});var t=Z(i);return t?[t]:[]},[i]),y=(0,r.useMemo)(function(){return c.map(function(e){return{label:e.llmServiceTitle,options:e.enabledModels.map(function(t){return{label:"".concat(e.llmServiceTitle," / ").concat(t.label),value:"".concat(e.llmService,":").concat(t.value)}})}})},[c]),b=(0,r.useMemo)(function(){var e=new Map;return y.forEach(function(t){t.options.forEach(function(t){return e.set(t.value,t.label)})}),e},[y]),g=(0,r.useCallback)(function(e){var n=k({},ee(t.getFieldValue("modelSettings")),e);u(n),t.setFieldsValue({modelSettings:n})},[t]);return(0,r.useEffect)(function(){u(ee(n))},[n]),(0,r.useEffect)(function(){if(f&&!p.length&&y.length){var e,t,n,r=null==(n=y[0])||null==(t=n.options)||null==(e=t[0])?void 0:e.value;r&&g({models:[J(r)]})}},[f,y,p.length,g]),l().createElement(l().Fragment,null,l().createElement(a.Alert,{type:"info",showIcon:!0,message:e("Restrict this AI employee to the selected models.")}),l().createElement(a.Form.Item,{label:l().createElement(a.Typography.Text,{strong:!0},M(e("Enable dedicated model configuration"))),preserve:!0},l().createElement(a.Switch,{checked:f,onChange:function(e){return g({enabled:e})}})),l().createElement(a.Form.Item,{label:l().createElement(a.Typography.Text,{strong:!0},M(e("Models"))),preserve:!0},l().createElement(a.Select,{allowClear:!0,disabled:!f,loading:d,mode:"multiple",notFoundContent:d?l().createElement(a.Spin,{size:"small"}):null,optionFilterProp:"label",options:y,placeholder:e("Select models"),showSearch:!0,tagRender:function(e){return l().createElement(a.Tag,{closable:e.closable,onClose:e.onClose},b.get(String(e.value))||e.label)},value:p,onChange:function(e){e.length?g({llmService:void 0,model:void 0,models:e.map(J)}):g({llmService:void 0,model:void 0,models:[]})}})))}),ea=function(){var e=(0,m.kj)();return function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return t?e(t):n}},eo=function(e){var t=e.title,n=e.description,r=a.theme.useToken().token;return l().createElement("div",null,l().createElement("div",{style:{fontWeight:r.fontWeightStrong,fontSize:r.fontSizeSM}},t),l().createElement("div",{style:{color:r.colorTextSecondary,fontSize:r.fontSizeSM}},n))},ei=(0,c.observer)(function(e){var t,n=e.builtIn,o=(0,m.kj)(),i=ea(),u=(0,f.M)(),s=a.Form.useFormInstance(),c=null!=(t=a.Form.useWatch("skillSettings",{form:s,preserve:!0}))?t:{},d=Array.isArray(c.skills)?c.skills:[];(0,r.useEffect)(function(){u.getAISkills().catch(function(e){console.error(e)})},[u]);var p=new Map(u.aiSkills.map(function(e){return[e.name,e]})),y=u.aiSkills.filter(function(e){return"GENERAL"===e.scope}),b=d.map(function(e){return p.get(e)}).filter(function(e){return!!e&&"SPECIFIED"===e.scope}),g=function(e){var t,n;return l().createElement(a.List.Item,{key:e.name},l().createElement("div",null,i(null!=(t=e.title)?t:e.name,e.name)),l().createElement(a.Typography.Text,{type:"secondary"},i(null!=(n=e.about)?n:e.description)))},h=[{key:"general-skills",label:l().createElement(eo,{title:o("General skills"),description:o("Shared by all AI employees.")}),children:l().createElement(a.List,{itemLayout:"vertical",size:"small",dataSource:y,renderItem:g})}];return n&&b.length&&h.push({key:"specific-skills",label:l().createElement(eo,{title:o("Employee-specific skills"),description:o("Only available to this AI employee.")}),children:l().createElement(a.List,{itemLayout:"vertical",size:"small",dataSource:b,renderItem:g})}),u.aiSkillsLoading?l().createElement(a.Spin,null):l().createElement(a.Collapse,{ghost:!0,size:"small",defaultActiveKey:[],items:h})}),eu=function(e,t){return"CUSTOM"===e.scope?(null==t?void 0:t.autoCall)?"ALLOW":"ASK":"ALLOW"===e.defaultPermission?"ALLOW":"ASK"},es=(0,c.observer)(function(e){var t=e.builtIn,n=(0,m.kj)(),i=a.theme.useToken().token,u=ea(),s=(0,f.M)(),c=a.Form.useFormInstance(),d=a.Form.useWatch("skillSettings",{form:c,preserve:!0}),p=I((0,r.useState)(function(){return en(c.getFieldValue("skillSettings"))}),2),y=p[0],b=p[1],g=Array.isArray(y.tools)?y.tools:[],h=I((0,r.useState)(t&&!g.length?[]:["custom-tools"]),2),v=h[0],E=h[1],S=l().useRef(g.length),C=[{label:n("Ask"),value:"ASK"},{label:n("Allow"),value:"ALLOW"}];(0,r.useEffect)(function(){s.refreshAITools().catch(function(e){console.error(e)})},[s]),(0,r.useEffect)(function(){b(en(d))},[d]);var F=function(e){var t=w(k({},en(c.getFieldValue("skillSettings"))),{tools:e});b(t),c.setFieldsValue({skillSettings:t})},x=new Set(g.map(function(e){return e.name})),T=new Map(s.aiTools.map(function(e){return[e.definition.name,e]})),O=s.aiTools.filter(function(e){return"GENERAL"===e.scope&&"loader"===e.from}),B=g.filter(function(e){var t=T.get(e.name);return t&&"GENERAL"!==t.scope&&"CUSTOM"!==t.scope}),M=g.filter(function(e){var t=T.get(e.name);return!t||"CUSTOM"===t.scope});(0,r.useEffect)(function(){var e=0===S.current;t&&0===M.length?E([]):e&&M.length>0&&E(["custom-tools"]),S.current=M.length},[t,M.length]);var P=s.aiTools.filter(function(e){return"CUSTOM"===e.scope&&!x.has(e.definition.name)}).map(function(e){var t,n,r,o;return{key:e.definition.name,label:l().createElement("div",{style:{maxWidth:8*i.controlHeightLG,minWidth:4*i.controlHeightLG}},l().createElement(a.Flex,{justify:"space-between"},l().createElement("div",null,u(null!=(t=null==(r=e.introduction)?void 0:r.title)?t:e.definition.name,e.definition.name))),l().createElement(a.Typography.Text,{type:"secondary"},u(null!=(n=null==(o=e.introduction)?void 0:o.about)?n:e.definition.description))),onClick:function(){var t=en(c.getFieldValue("skillSettings")),n=Array.isArray(t.tools)?t.tools:[];n.some(function(t){return t.name===e.definition.name})||F(A(n).concat([{name:e.definition.name,autoCall:!1}]))}}}),j=function(e){var t,r,o,i,s="definition"in e?e:T.get(e.name);if(!s)return null;var c="definition"in e?void 0:e;return l().createElement(a.List.Item,{key:s.definition.name,extra:l().createElement(a.Flex,{vertical:!0,justify:"end"},l().createElement(a.Space,null,l().createElement(a.Typography.Text,{type:"secondary"},n("Permission")),l().createElement(a.Segmented,{size:"small",options:C,value:eu(s,c),disabled:!0})))},l().createElement("div",null,u(null!=(t=null==(o=s.introduction)?void 0:o.title)?t:s.definition.name,s.definition.name)),l().createElement(a.Typography.Text,{type:"secondary"},u(null!=(r=null==(i=s.introduction)?void 0:i.about)?r:s.definition.description)))},L=[{key:"general-tools",label:l().createElement(eo,{title:n("General tools"),description:n("Shared by all AI employees.")}),children:l().createElement(a.List,{itemLayout:"vertical",size:"small",dataSource:O,renderItem:j})}];return t&&B.length&&L.push({key:"specific-tools",label:l().createElement(eo,{title:n("Employee-specific tools"),description:n("Only available to this AI employee.")}),children:l().createElement(a.List,{itemLayout:"vertical",size:"small",dataSource:B,renderItem:j})}),L.push({key:"custom-tools",label:l().createElement(eo,{title:n("Custom tools"),description:n("Created by workflow. You can add/remove and set default permissions.")}),extra:l().createElement("div",{onClick:function(e){e.stopPropagation()},onKeyDown:function(e){e.stopPropagation()}},l().createElement(a.Dropdown,{menu:{items:P},disabled:!(null==P?void 0:P.length),placement:"bottomRight"},l().createElement(a.Button,{type:"primary",icon:l().createElement(o.PlusOutlined,null),disabled:!(null==P?void 0:P.length),style:{pointerEvents:(null==P?void 0:P.length)?void 0:"none"}},n("Add tool")))),children:l().createElement(a.List,{itemLayout:"vertical",bordered:!0,dataSource:M,renderItem:function(e){var t,r,i,s,c=T.get(e.name),m=c?u(null!=(t=null==(i=c.introduction)?void 0:i.title)?t:c.definition.name,c.definition.name):e.name,d=c?u(null!=(r=null==(s=c.introduction)?void 0:s.about)?r:c.definition.description):null;return l().createElement(a.List.Item,{key:e.name,extra:l().createElement(a.Space,null,l().createElement(a.Typography.Text,null,n("Permission")),l().createElement(a.Segmented,{size:"small",options:C,value:c?eu(c,e):e.autoCall?"ALLOW":"ASK",onChange:function(t){F(g.map(function(n){return n.name===e.name?w(k({},n),{autoCall:"ALLOW"===t}):n}))}}),l().createElement(a.Button,{"aria-label":n("Delete"),icon:l().createElement(o.DeleteOutlined,null),type:"text",onClick:function(){F(g.filter(function(t){return t.name!==e.name}))}}))},l().createElement("div",null,m),d?l().createElement(a.Typography.Text,{type:"secondary"},d):null)}})}),s.aiToolsLoading?l().createElement(a.Spin,null):l().createElement(a.Collapse,{ghost:!0,size:"small",activeKey:v,onChange:function(e){return E(Array.isArray(e)?e.map(String):[String(e)])},items:L})}),ec=function(e){var t=e.apiClient,n=(0,m.kj)(),o=a.Form.useFormInstance(),i=a.Form.useWatch("enableKnowledgeBase",o),u=I((0,r.useState)([]),2),s=u[0],c=u[1],d=I((0,r.useState)(!1),2),f=d[0],p=d[1];return(0,r.useEffect)(function(){var e=!1;return v(function(){var n;return F(this,function(r){switch(r.label){case 0:p(!0),r.label=1;case 1:return r.trys.push([1,3,4,5]),[4,X(t)];case 2:return n=r.sent(),e||c(n),[3,5];case 3:return console.error(r.sent()),[3,5];case 4:return e||p(!1),[7];case 5:return[2]}})})().catch(function(e){console.error(e)}),function(){e=!0}},[t]),l().createElement(l().Fragment,null,l().createElement(a.Form.Item,{name:"enableKnowledgeBase",label:M(n("Enable Knowledge Base")),valuePropName:"checked",preserve:!0},l().createElement(a.Switch,null)),l().createElement(a.Form.Item,{name:"knowledgeBasePrompt",label:M(n("Knowledge Base Prompt")),rules:[{required:!0}],preserve:!0},l().createElement(a.Input.TextArea,{disabled:!i,autoSize:{minRows:5}})),l().createElement(a.Form.Item,{name:["knowledgeBase","knowledgeBaseKeys"],label:M(n("Knowledge Base")),rules:[{required:!!i}],preserve:!0},l().createElement(a.Select,{disabled:!i,fieldNames:{label:"name",value:"key"},loading:f,mode:"multiple",options:s})),l().createElement(a.Form.Item,{name:["knowledgeBase","topK"],label:M(n("Top K")),rules:[{required:!0}],preserve:!0},l().createElement(a.InputNumber,{disabled:!i,min:1,max:100})),l().createElement(a.Form.Item,{name:["knowledgeBase","score"],label:M(n("Score")),rules:[{required:!0}],preserve:!0},l().createElement(a.InputNumber,{disabled:!i,min:0,max:1,step:.1})))},em=function(e){var t,n=e.apiClient,r=e.activeTab,o=e.edit,i=e.onTabChange,u=e.record,s=e.knowledgeBaseEnabled,c=(0,m.kj)(),d=a.Form.useFormInstance(),f=null!=(t=a.Form.useWatch("chatSettings",d))?t:{},p=!!(null==u?void 0:u.builtIn),y=!1!==f.enableSkills,b=!1!==f.enableTools;return l().createElement(a.Tabs,{activeKey:r,onChange:i,items:[{key:"profile",label:c("Profile"),children:l().createElement(Q,{edit:o,builtIn:p}),forceRender:!0},{key:"roleSetting",label:c("Role setting"),children:l().createElement($,{builtIn:p,record:u}),forceRender:!0},{key:"modelSettings",label:c("Model settings"),children:l().createElement(el,null),forceRender:!0}].concat(A(y?[{key:"skills",label:c("Skills"),children:l().createElement(ei,{builtIn:p}),forceRender:!0}]:[]),A(b?[{key:"tools",label:c("Tools"),children:l().createElement(es,{builtIn:p}),forceRender:!0}]:[]),A(s?[{key:"knowledgeBase",label:c("KnowledgeBase"),children:l().createElement(ec,{apiClient:n}),forceRender:!0}]:[]))})},ed=function(e){var t=e.record,n=e.onUpdated,o=(0,s.useApp)(),i=(0,m.kj)(),u=a.App.useApp().message,c=(0,f.M)(),d=I((0,r.useState)(!1),2),p=d[0],y=d[1];return l().createElement(a.Switch,{checked:!!t.enabled,onChange:function(e){return v(function(){return F(this,function(r){switch(r.label){case 0:y(!0),r.label=1;case 1:return r.trys.push([1,5,6,7]),[4,U(o.apiClient,t.username,e)];case 2:return r.sent(),u.success(i("Saved successfully")),[4,n()];case 3:return r.sent(),[4,c.refreshAIEmployees()];case 4:return r.sent(),[3,7];case 5:return console.error(r.sent()),u.error(i("Failed to update")),[3,7];case 6:return y(!1),[7];case 7:return[2]}})})()},loading:p,size:"small"})},ef=function(){var e=(0,s.useApp)(),t=(0,c.useFlowContext)(),n=(0,m.kj)(),u=a.theme.useToken().token,y=a.App.useApp().message,b=(0,f.M)(),g=I((0,r.useState)("business"),2),h=g[0],E=g[1],S=I((0,r.useState)([]),2),k=S[0],w=S[1],A=I((0,r.useState)(!1),2),C=A[0],x=A[1],T=I((0,r.useState)(!1),2),O=T[0],B=T[1],M=I((0,r.useState)([]),2),j=M[0],L=M[1],R=e.apiClient.auth,K=(null==R?void 0:R.role)==="root",z=(0,r.useMemo)(function(){return{color:u.colorPrimary,marginInline:-u.paddingSM,paddingBlock:u.paddingSM,paddingInlineEnd:u.paddingXS+u.paddingSM,paddingInlineStart:u.paddingSM}},[u.colorPrimary,u.paddingSM,u.paddingXS]),W=(0,r.useCallback)(function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:h;return v(function(){return F(this,function(n){switch(n.label){case 0:x(!0),n.label=1;case 1:return n.trys.push([1,,3,4]),[4,G(e.apiClient,{category:t})];case 2:return w(n.sent().data),[3,4];case 3:return x(!1),[7];case 4:return[2]}})})()},[e.apiClient,h]);(0,r.useEffect)(function(){W().catch(function(e){console.error(e),x(!1)})},[W]),(0,r.useEffect)(function(){v(function(){return F(this,function(t){switch(t.label){case 0:return t.trys.push([0,2,,3]),[4,q(e.apiClient)];case 1:return B.apply(void 0,[t.sent()]),[3,3];case 2:return console.error(t.sent()),[3,3];case 3:return[2]}})})().catch(function(e){console.error(e)})},[e.apiClient]);var D=function(e){t.viewer.open({type:"drawer",width:p.o,closable:!0,content:l().createElement(ep,{editingRecord:e,knowledgeBaseEnabled:O,onSubmitted:function(){return v(function(){return F(this,function(e){switch(e.label){case 0:return[4,W()];case 1:return e.sent(),[4,b.refreshAIEmployees()];case 2:return e.sent(),[2]}})})()}})})},V=[{title:n("Avatar"),dataIndex:"avatar",render:function(e){return e?l().createElement(a.Avatar,{shape:"circle",size:"large",src:(0,d.H)(e)}):null}},{title:n("Username"),dataIndex:"username",render:function(e,t){var r=t.missingKnowledgeBaseKeys||[];return r.length?l().createElement(a.Space,{size:"small"},l().createElement("span",null,e),l().createElement(a.Tooltip,{title:n("Missing knowledge base configuration for keys: {{keys}}. Create knowledge bases with the same keys to enable this employee normally.",{keys:r.join(", ")})},l().createElement(o.ExclamationCircleOutlined,null))):e}},{title:n("Nickname"),dataIndex:"nickname"},{title:n("Position"),dataIndex:"position"},{title:n("Enabled"),dataIndex:"enabled",render:function(e,t){return l().createElement(ed,{record:t,onUpdated:function(){return W()}})}},{title:n("Actions"),key:"actions",render:function(t,r){return l().createElement(a.Space,{size:u.marginXS},l().createElement("a",{style:z,onClick:function(){return D(r)}},n("Edit")),l().createElement(a.Popconfirm,{title:n("Delete AI employee"),description:n("Are you sure you want to delete this AI employee?"),onConfirm:function(){return v(function(){return F(this,function(t){switch(t.label){case 0:if(r.builtIn&&!K)return y.warning(n("Cannot delete built-in ai employees")),[2];return[4,N(e.apiClient,r.username)];case 1:return t.sent(),y.success(n("Saved successfully")),[4,W()];case 2:return t.sent(),[4,b.refreshAIEmployees()];case 3:return t.sent(),[2]}})})()}},l().createElement("a",{style:z},n("Delete"))))}}];return l().createElement(a.Card,{style:{display:"flex",flexDirection:"column",minHeight:"100%"},styles:{body:{display:"flex",flex:1,flexDirection:"column",minHeight:0}}},l().createElement(a.Flex,{vertical:!0,gap:"middle",style:{flex:1,minHeight:0}},l().createElement(a.Flex,{justify:"space-between",wrap:"wrap",gap:"middle"},l().createElement(a.Radio.Group,{optionType:"button",value:h,options:[{label:n("Business"),value:"business"},{label:n("Developer"),value:"developer"}],onChange:function(e){return E(e.target.value)}}),l().createElement(a.Space,null,l().createElement(a.Button,{icon:l().createElement(o.ReloadOutlined,null),onClick:function(){return W()}},n("Refresh")),l().createElement(a.Button,{type:"primary",icon:l().createElement(o.PlusOutlined,null),onClick:function(){t.viewer.open({type:"drawer",width:p.o,closable:!0,content:l().createElement(ep,{knowledgeBaseEnabled:O,onSubmitted:function(){return v(function(){return F(this,function(e){switch(e.label){case 0:return[4,W()];case 1:return e.sent(),[4,b.refreshAIEmployees()];case 2:return e.sent(),[2]}})})()}})})}},n("New AI employee")))),l().createElement("div",{style:{display:"flex",flex:1,flexDirection:"column",minHeight:0}},l().createElement(s.Table,{rowKey:"username",loading:C,columns:V,dataSource:k,className:P,isDraggable:!0,onSortEnd:function(t,r){return v(function(){var l,a,o;return F(this,function(u){switch(u.label){case 0:if(!t.username||!r.username||t.username===r.username)return[2];l=k,a=k.findIndex(function(e){return e.username===t.username}),o=k.findIndex(function(e){return e.username===r.username}),a>=0&&o>=0&&w((0,i.arrayMove)(k,a,o)),u.label=1;case 1:return u.trys.push([1,5,,6]),[4,_(e.apiClient,t.username,r.username)];case 2:return u.sent(),y.success(n("Saved successfully")),[4,W()];case 3:return u.sent(),[4,b.refreshAIEmployees()];case 4:return u.sent(),[3,6];case 5:return console.error(u.sent()),w(l),y.error(n("Failed to update")),[3,6];case 6:return[2]}})})()},rowSelection:{selectedRowKeys:j,onChange:L},pagination:{defaultPageSize:20,showTotal:function(e){return n("Total {{count}} items",{count:e})}},scroll:{x:"max-content",y:"100%"}}))))},ep=function(e){var t=e.editingRecord,n=e.knowledgeBaseEnabled,o=e.onSubmitted,i=(0,s.useApp)(),u=(0,c.useFlowContext)(),d=(0,m.kj)(),f=a.App.useApp().message,p=I(a.Form.useForm(),1)[0],b=I((0,r.useState)(!1),2),g=b[0],h=b[1],E=I((0,r.useState)("profile"),2),S=E[0],A=E[1],C=I((0,r.useState)(!1),2),x=C[0],O=C[1],B=(0,r.useMemo)(function(){return t?w(k({},t),{_aboutMode:t.builtIn?t.about?"custom":"system":void 0}):{username:(0,c.randomId)(),enabled:!0,enableKnowledgeBase:!1,knowledgeBase:{knowledgeBaseKeys:[],topK:3,score:"0.6"},knowledgeBasePrompt:d("knowledge Base Prompt default"),avatar:T,builtIn:!1,category:"business"}},[t,d]),M=u.view,P=M.Header,j=M.Footer;(0,r.useEffect)(function(){p.setFieldsValue(B)},[p,B]);var L=(0,y.C)({view:u.view,form:p,initialValues:B,dirty:x,title:d("Unsaved changes"),content:d("Are you sure you don't want to save?")});return l().createElement(l().Fragment,null,l().createElement(P,{title:t?d("Edit AI employee"):d("New AI employee")}),l().createElement(a.Spin,{spinning:g},l().createElement(a.Form,{form:p,layout:"vertical",onFinish:function(e){return v(function(){var n,r;return F(this,function(l){switch(l.label){case 0:h(!0),l.label=1;case 1:if(l.trys.push([1,,8,9]),n=p.getFieldsValue(!0),r=w(k({},e),{skillSettings:en(n.skillSettings)}),!t)return[3,3];return[4,H(i.apiClient,r)];case 2:return l.sent(),[3,5];case 3:return[4,V(i.apiClient,r)];case 4:l.sent(),l.label=5;case 5:return f.success(d("Saved successfully")),[4,o()];case 6:return l.sent(),[4,u.view.close(void 0,!0)];case 7:return l.sent(),[3,9];case 8:return h(!1),[7];case 9:return[2]}})})()},onValuesChange:function(){return O(!0)}},l().createElement(em,{apiClient:i.apiClient,activeTab:S,edit:!!t,onTabChange:A,record:t,knowledgeBaseEnabled:n}))),l().createElement(j,null,l().createElement(a.Flex,{justify:"end",gap:"small"},l().createElement(a.Button,{onClick:L},d("Cancel")),l().createElement(a.Button,{type:"primary",loading:g,onClick:function(){return p.submit()}},d("Submit")))))};t.default=ef}}]);
|