@xpert-ai/plugin-sdk 3.21.0 → 3.21.1

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.
@@ -2,7 +2,9 @@
2
2
 
3
3
  ## Runtime capabilities
4
4
 
5
- See [platform capabilities and scoped factories](./runtime-capabilities.md) for domain registration, execution-scoped APIs and usage outside Agent middleware.
5
+ See [platform capabilities and scoped factories](./en/runtime-capabilities.md) for domain registration, execution-scoped APIs and usage outside Agent middleware.
6
+
7
+ See [knowledgebase APIs](./en/KNOWLEDGEBASE_API.md) for resource discovery, readiness, permissions and migration from legacy listing.
6
8
 
7
9
  ## Building
8
10
 
@@ -14,11 +16,11 @@ Run `nx test plugin-sdk` to execute the unit tests via [Jest](https://jestjs.io)
14
16
 
15
17
  ## Schema config
16
18
 
17
- [Schema UI 扩展规范](./SCHEMA_SPECIFICATION.md)
19
+ [Schema UI Extension Specification](./en/SCHEMA_SPECIFICATION.md)
18
20
 
19
21
  ## Permissions
20
22
 
21
- [插件权限设计指南](./PERMISSIONS.md)
23
+ [Plugin Permission Design Guide](./en/PERMISSIONS.md)
22
24
 
23
25
  ## Decorator-driven business Tools
24
26
 
@@ -115,13 +117,13 @@ For completed operations, `prepareToolResult(() => project(result), () => minima
115
117
 
116
118
  For a host-native MCP App, declare each static HTML bundle once in the Provider's `apps` array, then bind a Tool with `mcp.app.resourceKey` and include `app` visibility. The App key must exist in the same Provider and its entry must be a relative `.html` path inside the packaged plugin. The host publishes the bundle as a `ui://` resource; plugins must not create a stdio server or put CSP/credentials in Tool results.
117
119
 
118
- Agent middleware can also expose these Apps without a published Toolset. See [middleware Apps and post-tool continuation](./MIDDLEWARE_APPS.md) for `app` bindings and `interruptAfter` checkpoints.
120
+ Agent middleware can also expose these Apps without a published Toolset. See [middleware Apps and post-tool continuation](./en/MIDDLEWARE_APPS.md) for `app` bindings and `interruptAfter` checkpoints.
119
121
 
120
122
  The host owns the public MCP endpoint identity. It combines the plugin's stable `artifactNamespace`, the Provider key, and an opaque scope hash; client names and product-specific identifiers do not belong in the slug. A tenant- or system-level plugin has one tenant-scoped Publication and capability snapshot, while each organization receives an independent access grant and organization-bound credential. An organization-level plugin receives a dedicated organization-scoped Publication.
121
123
 
122
124
  ## View extensions
123
125
 
124
- [View Extension Protocol](./docs/view-extension-protocol.md)
126
+ [View Extension Protocol](./en/view-extension-protocol.md)
125
127
 
126
128
  ## Browser collaboration client
127
129
 
@@ -159,7 +161,7 @@ containing these interfaces. They are not part of the published SDK 3.18.3 basel
159
161
 
160
162
  ## Conversation resource receipts
161
163
 
162
- See [RESOURCE-CARDS.md](./RESOURCE-CARDS.md) for the public protocol, tool/middleware emitter, transactional Project provider example, and coordinated release order.
164
+ See [RESOURCE-CARDS.md](./en/RESOURCE-CARDS.md) for the public protocol, tool/middleware emitter, transactional Project provider example, and coordinated release order.
163
165
 
164
166
  ## Project task business types
165
167
 
@@ -175,7 +177,7 @@ export class ExampleTasks implements IProjectTaskProvider {
175
177
  {
176
178
  key: 'example.tasks.illustration',
177
179
  presentation: {
178
- label: { en_US: 'Construction images', zh_Hans: '施工配图' },
180
+ label: { en_US: 'Construction images' },
179
181
  icon: 'Images'
180
182
  }
181
183
  }
@@ -210,4 +212,4 @@ Deploy matching contracts, SDK and host support before a plugin starts emitting
210
212
 
211
213
  ## Tool image references
212
214
 
213
- See [TOOL-IMAGES.md](./TOOL-IMAGES.md) for `ToolImagesRuntimeCapability`, reference-only tool results, temporary visual model inputs, execution scope, and recovery rules. Never persist the messages returned by `prepareModelInput`.
215
+ See [TOOL-IMAGES.md](./en/TOOL-IMAGES.md) for `ToolImagesRuntimeCapability`, reference-only tool results, temporary visual model inputs, execution scope, and recovery rules. Never persist the messages returned by `prepareModelInput`.
@@ -0,0 +1,42 @@
1
+ # Knowledgebase resource discovery
2
+
3
+ `platform.knowledgebase` separates catalog discovery, metadata, permission inspection and content retrieval. All new catalog methods use the authenticated runtime's tenant, organization and actor. Inputs cannot select another identity or organization.
4
+
5
+ | Method | Responsibility |
6
+ | ----------- | ---------------------------------------------------------------------------------------------------------------------------- |
7
+ | `query` | Discover resources with explicit scope, metadata filters, required actions and cursor pagination. |
8
+ | `get` | Read one resource's safe metadata, supported ingestion capability, configuration and processing readiness. |
9
+ | `getAccess` | Inspect named actions for up to 100 resource IDs. Missing and inaccessible IDs both return `unavailable`. |
10
+ | `search` | Retrieve indexed content; its existing contract is unchanged. |
11
+ | `list` | Deprecated for new integrations; preserves the old scope, shared-library behavior and array result. Use `query` in new code. |
12
+
13
+ The draft-only `listWritable` method has been removed. Destination discovery uses `query` with required actions.
14
+
15
+ Document lifecycle methods remain on `platform.knowledgebase.documents`; administrative provisioning remains on `platform.knowledgebase.provisioning`. Resource discovery does not create or connect libraries.
16
+
17
+ ## Discover a destination
18
+
19
+ Feature-detect `query`, `get` and `getAccess` before using them on an older host. A workflow requiring write authorization must fail explicitly when these methods are absent; the old `list` is not an authorization substitute.
20
+
21
+ ```ts
22
+ const actions: KnowledgebaseAction[] = ['documents.create', 'documents.process']
23
+ const page = await api.query({
24
+ scope: { kind: 'workspace', workspaceId, relation: 'owned' },
25
+ filter: {
26
+ visibility: 'organization',
27
+ applicationTags: { allOf: [imageLibraryTag] }
28
+ },
29
+ access: { requireAll: actions },
30
+ page: { limit: 100, cursor }
31
+ })
32
+ ```
33
+
34
+ - `owned` restricts results to the selected workspace. `available` also considers organization/public resources in the current organization, subject to point-read authorization. It does not grant access to another workspace or include tenant libraries implicitly.
35
+ - `organization` searches the current organization. `tenant` searches tenant-owned public libraries. No scope bypasses resource permissions.
36
+ - Text filtering is a literal substring of name/description; `applicationTags.allOf` requires every tag. Publication and visibility are separate filters.
37
+ - Page limits are 1–100 (default 20), with stable ascending ID keysets. Follow `nextCursor` even after a short or empty page; each request scans at most 1,000 rows. Only `null` confirms exhaustion.
38
+ - Cursors are bound to tenant, organization, actor, scope, filters and required actions. Changing these requires restarting the query. Permissions are evaluated again on every page. Pagination is not a database snapshot; insertions before the current ID may appear only in a fresh query.
39
+
40
+ Before starting paid work, inspect `getAccess` for every required action and `get` for readiness. `configuration.embeddingConfigured` means an embedding model binding exists, not that an external provider is currently healthy. Recheck access before saving, and retain normal authorization on actual document writes; an earlier check never authorizes a later write.
41
+
42
+ Catalog responses expose neither provider credentials nor model bindings. Current document/chunk mutations use the platform's existing knowledgebase write policy; exposing distinct action names allows future permission refinement without adding action-specific list methods.
@@ -0,0 +1,173 @@
1
+ # Plugin Permission Design Guide
2
+
3
+ Declare model requirements in a strategy's `meta.permissions` and expose provider/model selection in `configSchema`. The host resolves the user's configuration and credentials, creates the appropriate model client, and injects it into `config.client` before calling `understandImages`.
4
+
5
+ The following design illustrates how `OpenAIGPT4VStrategy` can request a host-provided client instead of constructing its own OpenAI, Anthropic or other vision-model client.
6
+
7
+ ## Strategy definition
8
+
9
+ ```ts
10
+ import { Injectable } from '@nestjs/common'
11
+ import { Document } from 'langchain/document'
12
+ import {
13
+ ImageUnderstandingStrategy,
14
+ IImageUnderstandingStrategy,
15
+ TImageUnderstandingFile,
16
+ TImageUnderstandingResult
17
+ } from './strategy.interface'
18
+
19
+ @Injectable()
20
+ @ImageUnderstandingStrategy('openai-gpt4v')
21
+ export class OpenAIGPT4VStrategy implements IImageUnderstandingStrategy<any> {
22
+ readonly meta = {
23
+ name: 'openai-gpt4v',
24
+ label: { en: 'OpenAI GPT-4 Vision' },
25
+
26
+ /**
27
+ * Declare the plugin's requirement for "llm" access,
28
+ * with OpenAI as the provider and vision as the capability.
29
+ * The host uses config.provider and config.model to create the client
30
+ * and inject it into config.client.
31
+ */
32
+ permissions: [
33
+ {
34
+ type: 'llm',
35
+ provider: 'openai',
36
+ capability: 'vision'
37
+ }
38
+ ],
39
+
40
+ /**
41
+ * The configuration schema requires provider and model.
42
+ * The host uses these settings and the user's API key
43
+ * to create and inject the client.
44
+ */
45
+ configSchema: {
46
+ type: 'object',
47
+ properties: {
48
+ provider: {
49
+ type: 'string',
50
+ enum: ['openai'],
51
+ description: 'Model provider'
52
+ },
53
+ model: {
54
+ type: 'string',
55
+ default: 'gpt-4-vision-preview',
56
+ description: 'Model name'
57
+ },
58
+ prompt: {
59
+ type: 'string',
60
+ default: 'Describe this image in detail.',
61
+ description: 'Prompt for the image understanding task'
62
+ }
63
+ },
64
+ required: ['provider', 'model']
65
+ },
66
+
67
+ icon: {
68
+ svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><circle cx="10" cy="10" r="8" stroke="black" fill="none"/><text x="6" y="14">VLM</text></svg>',
69
+ color: '#10a37f'
70
+ }
71
+ }
72
+
73
+ async validateConfig(config: any): Promise<void> {
74
+ if (!config.client) {
75
+ throw new Error('Missing injected LLM client in config. Core system must inject client.')
76
+ }
77
+ }
78
+
79
+ async understandImages(files: TImageUnderstandingFile[], config: any): Promise<TImageUnderstandingResult[]> {
80
+ const client = config.client // Injected by the host.
81
+ const results: TImageUnderstandingResult[] = []
82
+
83
+ for (const file of files) {
84
+ const description = await this.runGPT4V(client, file.path, config)
85
+
86
+ const doc = new Document({
87
+ pageContent: description,
88
+ metadata: {
89
+ chunkId: `img-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
90
+ parentChunkId: file.parentChunkId,
91
+ imagePath: file.path,
92
+ source: file.filename,
93
+ type: 'vlm',
94
+ engine: config.model
95
+ }
96
+ })
97
+
98
+ results.push({
99
+ docs: [doc],
100
+ metadata: { engine: config.model, file: file.filename }
101
+ })
102
+ }
103
+
104
+ return results
105
+ }
106
+
107
+ private async runGPT4V(client: any, imagePath: string, config: any): Promise<string> {
108
+ // The host has already created this OpenAI client.
109
+ const response = await client.chat.completions.create({
110
+ model: config.model,
111
+ messages: [
112
+ {
113
+ role: 'user',
114
+ content: [
115
+ { type: 'text', text: config.prompt || 'Describe this image in detail.' },
116
+ { type: 'image_url', image_url: { url: imagePath } }
117
+ ]
118
+ }
119
+ ],
120
+ max_tokens: 500
121
+ })
122
+
123
+ return response.choices[0]?.message?.content || ''
124
+ }
125
+ }
126
+ ```
127
+
128
+ ---
129
+
130
+ ## Host processing
131
+
132
+ - Read the plugin's `meta.permissions` to identify the requirement:
133
+
134
+ ```json
135
+ { "type": "llm", "provider": "openai", "capability": "vision" }
136
+ ```
137
+
138
+ - Use the user's `config.provider = "openai"` and `config.model = "gpt-4-vision-preview"`
139
+ to instantiate `OpenAI({ apiKey: userApiKey })`.
140
+ - Inject the client into `config.client`.
141
+ - Call `strategy.understandImages(files, config)`.
142
+
143
+ ---
144
+
145
+ ## Usage example
146
+
147
+ ```ts
148
+ const strategy = this.imageUnderstandingRegistry.get('openai-gpt4v')
149
+ const result = await strategy.understandImages(
150
+ [
151
+ {
152
+ path: 'https://example.com/chart.png',
153
+ filename: 'chart.png',
154
+ extname: 'png',
155
+ parentChunkId: 'uuid-123'
156
+ }
157
+ ],
158
+ {
159
+ provider: 'openai',
160
+ model: 'gpt-4-vision-preview',
161
+ prompt: 'Describe this image in detail in English.',
162
+ client: openaiClient // Injected by the host.
163
+ }
164
+ )
165
+
166
+ console.log(result[0].docs[0].pageContent)
167
+ ```
168
+
169
+ ---
170
+
171
+ The plugin declares its permission requirements and provider/model configuration; the host supplies the appropriate client without requiring plugin-specific OpenAI initialization logic.
172
+
173
+ A shared permission-request interface, such as `ILLMPermissionRequest`, can give OCR, vision-model and embedding plugins a common way to declare dependencies.
@@ -205,15 +205,15 @@ For example, add this `content` property to the card passed to `emitResourceCard
205
205
 
206
206
  ```ts
207
207
  content: [
208
- { kind: 'fields', fields: [{ label: '状态', value: '已完成' }] },
208
+ { kind: 'fields', fields: [{ label: 'Status', value: 'Completed' }] },
209
209
  {
210
210
  kind: 'image-gallery',
211
- title: '施工配图',
211
+ title: 'Construction images',
212
212
  images: [
213
213
  {
214
214
  id: 'site-layout',
215
- title: '施工现场平面布置图',
216
- alt: '施工分区、出入口和运输路线',
215
+ title: 'Construction site layout',
216
+ alt: 'Work zones, entrances, exits and transport routes',
217
217
  file: {
218
218
  viewKey: 'bid.view-provider__bid.studio',
219
219
  fileKey: 'bid-project-image',
@@ -358,4 +358,4 @@ The built-in `platform.agent-invocation/execution` provider owns direct Coding i
358
358
 
359
359
  The card opens `platform.coding-execution__execution` with the exact invocation ID. Public CLI activity is written through the optional Runtime `context.activity` recorder and queried by the View provider. Resource-card refresh contains only presentation/state/target updates; it does not transport command output or invoke a CLI. Final summary cards are suppressed only when a Coding execution card already covers the run; independently delivered files retain their own cards.
360
360
 
361
- See [Coding Execution View](../server-ai/src/agent-invocation/execution-view/README.md) for the capability, authorization, storage, retention and navigation contract.
361
+ See [Coding Execution View](../../../server-ai/src/agent-invocation/execution-view/README.md) for the capability, authorization, storage, retention and navigation contract.
@@ -0,0 +1,325 @@
1
+ # Schema UI Extension Specification
2
+
3
+ Use a common UI extension across plugin configuration schemas so frontend renderers can apply consistent presentation and interaction rules.
4
+
5
+ Extend JSON Schema with the reserved `x-ui` field:
6
+
7
+ ```json
8
+ "x-ui": { ... }
9
+ ```
10
+
11
+ The frontend renderer uses `x-ui` to select components, present fields and apply dynamic dependencies.
12
+
13
+ ---
14
+
15
+ ## 1. Basic fields
16
+
17
+ | Field | Type | Description |
18
+ | -------------- | ------ | -------------------------------------------------------------------------------------------------------------------- |
19
+ | `component` | string | UI component type, such as `textInput`, `textarea`, `select`, `switch`, `slider`, `prompt-editor`, `ai-model-select` |
20
+ | `inputs` | object | Additional input properties for a custom component |
21
+ | `label` | string | Displayed field label |
22
+ | `description` | string | Help text; takes precedence over `schema.description` |
23
+ | `help` | string | Additional help, displayed as a help icon or tooltip when appropriate |
24
+ | `placeholder` | string | Input placeholder |
25
+ | `defaultValue` | any | Default value; takes precedence over `schema.default` |
26
+ | `order` | number | Display order in the UI |
27
+
28
+ ---
29
+
30
+ ## 2. Data sources
31
+
32
+ | Field | Type | Description |
33
+ | ------------ | ------ | -------------------------------------------------------------------------------------------------------------------------- |
34
+ | `options` | array | Static options for selects or multi-selects, such as `[{ label: 'OpenAI', value: 'openai' }]` |
35
+ | `enumLabels` | object | Map enum values to labels, for example `{ openai: 'OpenAI', azure: 'Azure OpenAI' }`, overriding the displayed enum labels |
36
+ | `dataSource` | string | Dynamic option source identifier, such as `"system.providers"`, `"system.models"` |
37
+ | `dependency` | string | Another field whose value filters the options, such as `"provider"` |
38
+ | `mapping` | object | Field mapping, for example `{ label: 'name', value: 'id' }` |
39
+
40
+ ---
41
+
42
+ ## 3. Validation and interaction
43
+
44
+ | Field | Type | Description |
45
+ | ------------- | ------- | ---------------------------------------------------------------------------------- |
46
+ | `required` | boolean | Whether the field is required; takes precedence over `schema.required` |
47
+ | `visibleWhen` | object | Display the field only when conditions match, for example `{ provider: 'openai' }` |
48
+ | `enabledWhen` | object | Enable the field when conditions match, for example `{ useCustomPrompt: true }` |
49
+ | `maxLength` | number | Maximum input length |
50
+ | `minLength` | number | Minimum input length |
51
+ | `regex` | string | Custom regular-expression validation rule |
52
+
53
+ ---
54
+
55
+ ## 4. Specialized components
56
+
57
+ ### `modelProviderSelect`
58
+
59
+ - Select a model provider, such as OpenAI, Anthropic, Azure or Ollama.
60
+ - `dataSource = "system.providers"`
61
+
62
+ ### `modelSelect`
63
+
64
+ - Select a specific model.
65
+ - Depends on `provider`.
66
+ - `dataSource = "system.models"`
67
+ - `dependency = "provider"`
68
+
69
+ ### `promptEditor`
70
+
71
+ - Edit prompts with multiline input, syntax highlighting and variable interpolation.
72
+
73
+ ### `jsonEditor`
74
+
75
+ - Edit JSON objects with format validation.
76
+
77
+ ### `codeEditor`
78
+
79
+ - Edit code with syntax highlighting, such as JavaScript, TypeScript or Python.
80
+
81
+ ---
82
+
83
+ ## 5. Example schema
84
+
85
+ ```ts
86
+ configSchema: {
87
+ type: 'object',
88
+ properties: {
89
+ provider: {
90
+ type: 'string',
91
+ description: 'Model provider',
92
+ enum: ['openai', 'anthropic', 'azure', 'ollama'],
93
+ 'x-ui': {
94
+ component: 'modelProviderSelect',
95
+ label: 'Provider',
96
+ order: 1,
97
+ dataSource: 'system.providers'
98
+ }
99
+ },
100
+ model: {
101
+ type: 'string',
102
+ description: 'Model name',
103
+ default: 'gpt-4-vision-preview',
104
+ 'x-ui': {
105
+ component: 'modelSelect',
106
+ label: 'Model',
107
+ order: 2,
108
+ dependency: 'provider',
109
+ dataSource: 'system.models'
110
+ }
111
+ },
112
+ prompt: {
113
+ type: 'string',
114
+ default: 'Describe this image in detail.',
115
+ description: 'Prompt',
116
+ 'x-ui': {
117
+ component: 'promptEditor',
118
+ label: 'Prompt',
119
+ order: 3,
120
+ placeholder: 'Enter a prompt; {{variables}} placeholders are supported'
121
+ }
122
+ },
123
+ temperature: {
124
+ type: 'number',
125
+ default: 0.7,
126
+ 'x-ui': {
127
+ component: 'slider',
128
+ label: 'Temperature',
129
+ order: 4,
130
+ min: 0,
131
+ max: 1,
132
+ step: 0.1
133
+ }
134
+ },
135
+ advanced: {
136
+ type: 'object',
137
+ 'x-ui': {
138
+ component: 'jsonEditor',
139
+ label: 'Advanced Config',
140
+ order: 5,
141
+ visibleWhen: { provider: 'openai' }
142
+ }
143
+ }
144
+ },
145
+ required: ['provider', 'model']
146
+ }
147
+ ```
148
+
149
+ ---
150
+
151
+ With these conventions:
152
+
153
+ - Renderers select the component from `x-ui.component`; the remaining `x-ui` properties drive its behavior.
154
+ - Plugin developers declare a schema to obtain a consistent configuration experience.
155
+ - The same conventions can support embedding, OCR, vision-model and vector-store plugins.
156
+
157
+ ## Representing secret input fields
158
+
159
+ Secret fields, such as API keys, tokens and passwords, need explicit UI handling:
160
+
161
+ 1. Render a password input (`type="password"`) or masked value.
162
+ 2. Represent a stored secret with `"******"` or an empty placeholder instead of returning its plaintext value.
163
+ 3. Mark secret fields in the schema so renderers can recognize them.
164
+
165
+ ---
166
+
167
+ ## Secret-field extension
168
+
169
+ Set `component: "secretInput"` in `x-ui` and support these properties:
170
+
171
+ | Field | Type | Description |
172
+ | ------------- | ------- | --------------------------------------------------------------------------------- |
173
+ | `component` | string | Set to `"secretInput"` to render a password input |
174
+ | `label` | string | Field label |
175
+ | `description` | string | Field description |
176
+ | `placeholder` | string | Placeholder, such as `Enter API key` |
177
+ | `revealable` | boolean | Whether a button may temporarily reveal the value |
178
+ | `maskSymbol` | string | Mask character (default: `*`) |
179
+ | `persist` | boolean | Whether to persist the value; false means runtime-only use without saving to disk |
180
+
181
+ ---
182
+
183
+ ## Example schema
184
+
185
+ ```ts
186
+ configSchema: {
187
+ type: 'object',
188
+ properties: {
189
+ apiKey: {
190
+ type: 'string',
191
+ description: 'OpenAI API Key',
192
+ 'x-ui': {
193
+ component: 'secretInput',
194
+ label: 'API Key',
195
+ placeholder: 'Enter your OpenAI API key',
196
+ revealable: true,
197
+ maskSymbol: '*',
198
+ persist: true
199
+ }
200
+ },
201
+ provider: {
202
+ type: 'string',
203
+ enum: ['openai', 'anthropic', 'azure'],
204
+ 'x-ui': {
205
+ component: 'modelProviderSelect',
206
+ label: 'Provider'
207
+ }
208
+ }
209
+ },
210
+ required: ['apiKey', 'provider']
211
+ }
212
+ ```
213
+
214
+ ---
215
+
216
+ ## Frontend presentation
217
+
218
+ - Render `apiKey` as a password input, masked by default.
219
+ - When `revealable: true`, provide a reveal/hide toggle.
220
+ - During editing, `"******"` indicates an existing value. Leaving it unchanged preserves that value.
221
+
222
+ ---
223
+
224
+ ## Secret handling
225
+
226
+ - When the form submits `apiKey === "******"`, preserve the stored value.
227
+ - Replace the stored value when a new value is submitted.
228
+ - Omit secret fields from logs and configuration exports.
229
+
230
+ ---
231
+
232
+ A shared interface such as `ISchemaSecretField` makes secret-specific behavior explicit.
233
+
234
+ ## Shared interface
235
+
236
+ Secret fields share the base UI contract while declaring the additional handling required for sensitive values.
237
+
238
+ ---
239
+
240
+ ### Interface design
241
+
242
+ ```ts
243
+ /**
244
+ * Base UI schema field definition
245
+ */
246
+ export interface ISchemaUIBase {
247
+ component: string // UI component type
248
+ label?: string // Field label
249
+ description?: string // Field description
250
+ placeholder?: string // Input placeholder
251
+ order?: number // UI display order
252
+ required?: boolean // Whether the field is required
253
+ visibleWhen?: Record<string, any> // Conditional visibility
254
+ enabledWhen?: Record<string, any> // Conditional enablement
255
+ }
256
+
257
+ /**
258
+ * Secret field extension
259
+ */
260
+ export interface ISchemaSecretField extends ISchemaUIBase {
261
+ component: 'secretInput' // Fixed component type
262
+ revealable?: boolean // Whether the reveal button is available
263
+ maskSymbol?: string // Mask character (default: *)
264
+ persist?: boolean // Whether to persist; false means runtime-only use
265
+ }
266
+ ```
267
+
268
+ Secret fields inherit the same base contract as ordinary fields, with additional properties for handling sensitive data.
269
+
270
+ ---
271
+
272
+ ### Usage example
273
+
274
+ ```ts
275
+ configSchema: {
276
+ type: 'object',
277
+ properties: {
278
+ apiKey: {
279
+ type: 'string',
280
+ description: 'OpenAI API Key',
281
+ 'x-ui': <ISchemaSecretField>{
282
+ component: 'secretInput',
283
+ label: 'API Key',
284
+ placeholder: 'Enter your OpenAI API key',
285
+ revealable: true,
286
+ maskSymbol: '*',
287
+ persist: true
288
+ }
289
+ },
290
+ provider: {
291
+ type: 'string',
292
+ enum: ['openai', 'anthropic', 'azure'],
293
+ 'x-ui': {
294
+ component: 'modelProviderSelect',
295
+ label: 'Provider'
296
+ }
297
+ }
298
+ },
299
+ required: ['apiKey', 'provider']
300
+ }
301
+ ```
302
+
303
+ ---
304
+
305
+ ### Frontend behavior
306
+
307
+ 1. **Rendering:**
308
+ - Render `secretInput` as a password field (`type=password`).
309
+ - Add a reveal toggle when `revealable: true`.
310
+
311
+ 2. **Loading configuration:**
312
+ - Treat `******` as an existing stored value without displaying the original content.
313
+
314
+ 3. **Saving configuration:**
315
+ - Preserve the stored value when the submitted value remains `******`.
316
+ - Replace the stored value when a new value is submitted.
317
+
318
+ 4. **Exporting configuration or logs:**
319
+ - Omit secret fields or output `******` to avoid disclosure.
320
+
321
+ ---
322
+
323
+ This makes `secretInput` a first-class, schema-driven UI component alongside `textInput` and `select`.
324
+
325
+ An `ISchemaUIComponent` union can describe the complete set of supported components, including selects, sliders, secret inputs and prompt editors.
@@ -1,7 +1,7 @@
1
1
  # Tool images with immutable references
2
2
 
3
3
  For the API responsibilities, image lifecycle, validation limits and server-only
4
- text-result policy, see the [tool images feature guide](../../docs/tool-images.md).
4
+ text-result policy, see the [tool images feature guide](../../../../docs/tool-images.md).
5
5
 
6
6
  Use `ToolImagesRuntimeCapability` inside an Agent middleware when a tool returns
7
7
  an image for visual inspection. The host stores validated image bytes in