@v587d/capital-generation 2.15.0 → 2.16.0
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/CHANGELOG.md +171 -0
- package/README.md +7 -12
- package/THIRD_PARTY_NOTICES.md +1 -0
- package/automation/TABLER-ICONS-LICENSE +21 -0
- package/automation/builtins.js +237 -10
- package/automation/client.js +79 -17
- package/automation/client.src.cjs +873 -210
- package/automation/contract.js +4 -0
- package/automation/defaults.js +6 -4
- package/automation/index.js +12 -7
- package/automation/package.json +5 -2
- package/automation/route.js +9 -2
- package/automation/runner.js +33 -6
- package/automation/scheduler.js +34 -29
- package/automation/schema.js +39 -5
- package/automation/service.js +102 -10
- package/automation/settings.js +6 -0
- package/automation/store.js +64 -21
- package/automation/task-icons.js +75 -0
- package/automation/workspaces.js +113 -13
- package/chart-ui/client.js +2 -2
- package/chart-ui/package.json +1 -1
- package/config/client.js +19 -5
- package/config/client.src.cjs +365 -44
- package/config/index.js +7 -5
- package/config/package.json +1 -1
- package/lib/agents/root-tool-policy.d.ts +3 -3
- package/lib/agents/root-tool-policy.js +4 -2
- package/lib/chart/runtime.d.ts +1 -1
- package/lib/chart/runtime.js +95 -0
- package/lib/chart/series.d.ts +4 -4
- package/lib/chart/series.js +44 -10
- package/lib/data-collector/dataset-tools.js +22 -0
- package/lib/data-collector/describe.js +1 -0
- package/lib/data-collector/hub.js +5 -0
- package/lib/data-collector/store.d.ts +5 -0
- package/lib/data-collector/store.js +17 -0
- package/lib/data-collector/time-axis.d.ts +15 -0
- package/lib/data-collector/time-axis.js +73 -0
- package/lib/data-collector/tools.d.ts +1 -1
- package/lib/data-collector/tools.js +12 -1
- package/lib/index.d.ts +5 -0
- package/lib/index.js +7 -5
- package/lib/sources/tencent-http.js +7 -2
- package/lib/sources/tencent-public-core.d.ts +2 -0
- package/lib/sources/tencent-public-core.js +5 -0
- package/lib/sources/wind-mcp.js +3 -3
- package/lib/sources-entry.d.ts +1 -1
- package/lib/web-retriever/local-fetch.d.ts +1 -1
- package/lib/web-retriever/local-fetch.js +1 -1
- package/lib/web-retriever/sources.d.ts +58 -0
- package/lib/web-retriever/sources.js +290 -0
- package/lib/web-retriever/tools.js +199 -8
- package/lib/web-retriever/wind-client.d.ts +1 -1
- package/lib/web-retriever/wind-client.js +1 -1
- package/package.json +1 -1
- package/preset/capital-generation/agent.patch.yml +20 -19
- package/preset/capital-generation/skills/capital-chart-protocol/SKILL.md +6 -3
- package/preset/capital-generation/skills/capital-data-protocol/SKILL.md +9 -2
- package/preset/capital-generation/skills/capital-orchestration/SKILL.md +2 -1
- package/preset/capital-generation/skills/capital-visualization-protocol/SKILL.md +2 -0
- package/preset/capital-generation/skills/capital-web-evidence/SKILL.md +18 -13
- package/preset/capital-generation/skills/capital-web-protocol/SKILL.md +30 -15
- package/watchlist/package.json +1 -1
package/config/client.src.cjs
CHANGED
|
@@ -9,6 +9,8 @@ const {
|
|
|
9
9
|
Switch,
|
|
10
10
|
Tag,
|
|
11
11
|
Modal,
|
|
12
|
+
Menu,
|
|
13
|
+
IconChevronDownOutlineRegular,
|
|
12
14
|
IconRightUpOutlineRegular,
|
|
13
15
|
} = require('@deepseek-ai/dsh-client-ui-primitives')
|
|
14
16
|
const { SELECTED_SKILL_CATALOG, SELECTED_SKILL_TAG_LABELS } = require('../selected-skills/catalog.js')
|
|
@@ -25,6 +27,7 @@ const {
|
|
|
25
27
|
SELECTED_SKILL_PRESET_ORDER,
|
|
26
28
|
SELECTED_SKILL_ROUTING,
|
|
27
29
|
} = require('../selected-skills/routing.js')
|
|
30
|
+
const { WORKSPACES_ROUTE } = require('../automation/contract.js')
|
|
28
31
|
|
|
29
32
|
/**
|
|
30
33
|
* Two different strings: `ENTRY_ID` is the settings namespace (= profile entry
|
|
@@ -64,14 +67,24 @@ const DOC_URLS = {
|
|
|
64
67
|
/** Render order = array order; one list drives status, refs, drafts and event refresh. */
|
|
65
68
|
const CREDENTIAL_FIELDS = ['fuyao', 'ftshare', 'anysearch', 'wind', 'paddleocr']
|
|
66
69
|
const AUTOMATION_FIELDS = ['tickMs', 'runTimeoutMinutes', 'idleTimeoutMinutes', 'maxSteps', 'maxToolCalls', 'inAppNotifications']
|
|
70
|
+
const AUTOMATION_WORKSPACE_FIELD = 'defaultWorkspaceId'
|
|
71
|
+
const WORKSPACE_DEDICATED_MENU_ID = '__capgen_dedicated_workspace__'
|
|
67
72
|
const AUTOMATION_DEFAULTS = {
|
|
68
73
|
tickMs: 60_000,
|
|
69
|
-
runTimeoutMinutes:
|
|
74
|
+
runTimeoutMinutes: 60,
|
|
70
75
|
idleTimeoutMinutes: 5,
|
|
71
76
|
maxSteps: 300,
|
|
72
77
|
maxToolCalls: 1_200,
|
|
73
78
|
inAppNotifications: true,
|
|
74
79
|
}
|
|
80
|
+
/** Mirrors `automation/defaults.js`; out-of-range values get an inline error instead of a silent clamp. */
|
|
81
|
+
const AUTOMATION_RANGES = {
|
|
82
|
+
tickMs: { min: 30_000, max: 3_600_000, unit: 'automationUnitMs' },
|
|
83
|
+
runTimeoutMinutes: { min: 5, max: 120, unit: 'automationUnitMinutes' },
|
|
84
|
+
idleTimeoutMinutes: { min: 1, max: 30, unit: 'automationUnitMinutes' },
|
|
85
|
+
maxSteps: { min: 100, max: 2_000, unit: 'automationUnitSteps' },
|
|
86
|
+
maxToolCalls: { min: 100, max: 5_000, unit: 'automationUnitCalls' },
|
|
87
|
+
}
|
|
75
88
|
const SELECTED_SKILL_FIELDS = SELECTED_SKILL_CATALOG.map(({ key }) => key)
|
|
76
89
|
// Stable orders: facet counts change with the other dimension, but chips must not jump under the cursor.
|
|
77
90
|
const SELECTED_SKILL_TRAITS = selectedSkillTraitOrder()
|
|
@@ -102,13 +115,27 @@ const zh = {
|
|
|
102
115
|
localFetchLabel: '允许启动本地提取网页内容',
|
|
103
116
|
localFetchHint: '开启后本地抓取兜底(回执来源 local-http)。保存后新自动模式会话生效。',
|
|
104
117
|
automationTitle: '投研自动化',
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
118
|
+
automationScheduleGroup: '调度',
|
|
119
|
+
automationRunGroup: '单次运行上限',
|
|
120
|
+
automationNotifyGroup: '通知',
|
|
121
|
+
automationInAppHint: '运行结束、失败或超时后,在应用内通知里留一条记录。',
|
|
122
|
+
automationTick: '自动检查间隔(毫秒)',
|
|
123
|
+
automationRunTimeout: '最长运行时间(分钟)',
|
|
124
|
+
automationInvalid: '请填写 {min}–{max} {unit}',
|
|
125
|
+
automationUnitMs: '毫秒',
|
|
126
|
+
automationUnitMinutes: '分钟',
|
|
127
|
+
automationUnitSteps: '步',
|
|
128
|
+
automationUnitCalls: '次',
|
|
108
129
|
automationIdleTimeout: '空闲超时(分钟)',
|
|
109
130
|
automationMaxSteps: '最大步骤',
|
|
110
131
|
automationMaxToolCalls: '最大工具调用',
|
|
111
132
|
automationInApp: '写入应用内通知',
|
|
133
|
+
automationDefaultWorkspace: '默认工作区',
|
|
134
|
+
automationWorkspacePath: '默认位置:{path}',
|
|
135
|
+
automationWorkspaceMissing: '原工作区已被移除,运行会回退到专属默认工作区。',
|
|
136
|
+
automationWorkspaceLoading: '工作区列表读取中…',
|
|
137
|
+
automationWorkspaceUnavailable: '工作区列表暂时读不到;任务仍会使用默认工作区,切回本格会重试。',
|
|
138
|
+
automationWorkspaceFallback: '专属默认工作区',
|
|
112
139
|
windLabel: 'Wind Alice API Key',
|
|
113
140
|
windHint: 'Wind 金融信披类文档检索接口。保存后新自动模式会话生效。',
|
|
114
141
|
paddleocrLabel: 'PaddleOCR 文档解析 Token',
|
|
@@ -136,7 +163,9 @@ const zh = {
|
|
|
136
163
|
save: '保存',
|
|
137
164
|
saving: '保存中…',
|
|
138
165
|
readOnly: '本部署的设置为只读。',
|
|
139
|
-
|
|
166
|
+
// A rejected or non-landing write (stale page revision, transport hiccup). Plain words only:
|
|
167
|
+
// the typed value is still there, so the next action is retry, not a restart.
|
|
168
|
+
saveFailed: '没有保存成功,请再试一次。',
|
|
140
169
|
unavailable: '该插件当前未加载,暂时无法配置。',
|
|
141
170
|
githubLabel: 'GitHub 仓库',
|
|
142
171
|
npmLabel: 'npm 包页面',
|
|
@@ -157,13 +186,27 @@ const en = {
|
|
|
157
186
|
localFetchLabel: 'Allow local web page extraction',
|
|
158
187
|
localFetchHint: 'When on, a failed fetch falls back to local direct fetching (receipt via: local-http). Takes effect in new Auto mode sessions.',
|
|
159
188
|
automationTitle: 'Research automation',
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
189
|
+
automationScheduleGroup: 'Scheduling',
|
|
190
|
+
automationRunGroup: 'Per-run limits',
|
|
191
|
+
automationNotifyGroup: 'Notifications',
|
|
192
|
+
automationInAppHint: 'Leave an in-app notification when a run finishes, fails, or times out.',
|
|
193
|
+
automationTick: 'Auto-check interval (ms)',
|
|
194
|
+
automationRunTimeout: 'Max run time (minutes)',
|
|
195
|
+
automationInvalid: 'Enter a whole number from {min} to {max} {unit}',
|
|
196
|
+
automationUnitMs: 'ms',
|
|
197
|
+
automationUnitMinutes: 'minutes',
|
|
198
|
+
automationUnitSteps: 'steps',
|
|
199
|
+
automationUnitCalls: 'calls',
|
|
163
200
|
automationIdleTimeout: 'Idle timeout (minutes)',
|
|
164
201
|
automationMaxSteps: 'Max steps',
|
|
165
202
|
automationMaxToolCalls: 'Max tool calls',
|
|
166
203
|
automationInApp: 'Write in-app notifications',
|
|
204
|
+
automationDefaultWorkspace: 'Default workspace',
|
|
205
|
+
automationWorkspacePath: 'Location: {path}',
|
|
206
|
+
automationWorkspaceMissing: 'That workspace was removed; runs fall back to the dedicated default workspace.',
|
|
207
|
+
automationWorkspaceLoading: 'Loading workspaces…',
|
|
208
|
+
automationWorkspaceUnavailable: 'The workspace list is unavailable; runs still use the default workspace. Re-entering this tab retries.',
|
|
209
|
+
automationWorkspaceFallback: 'Dedicated default workspace',
|
|
167
210
|
windLabel: 'Wind Alice API Key',
|
|
168
211
|
windHint: 'Wind financial disclosure document retrieval interface. Takes effect in new Auto mode sessions.',
|
|
169
212
|
paddleocrLabel: 'PaddleOCR document token',
|
|
@@ -191,7 +234,7 @@ const en = {
|
|
|
191
234
|
save: 'Save',
|
|
192
235
|
saving: 'Saving…',
|
|
193
236
|
readOnly: 'This deployment stores settings read-only.',
|
|
194
|
-
saveFailed: '
|
|
237
|
+
saveFailed: "That didn't save. Please try again.",
|
|
195
238
|
unavailable: 'This plugin is not loaded, so it cannot be configured right now.',
|
|
196
239
|
githubLabel: 'GitHub repository',
|
|
197
240
|
npmLabel: 'npm package page',
|
|
@@ -221,6 +264,7 @@ function installStyles() {
|
|
|
221
264
|
.capital-config-panel[hidden] { display: none; }
|
|
222
265
|
/* Host rows section: positive :has rules only, so any mismatch leaves it visible. */
|
|
223
266
|
[data-plugin-detail="${BUNDLE_NAME}"]:has(.capital-config-card[data-capital-config-tab="sources"]) section[data-plugin-rows] { display: none; }
|
|
267
|
+
[data-plugin-detail="${BUNDLE_NAME}"]:has(.capital-config-card[data-capital-config-tab="automation"]) section[data-plugin-rows] { display: none; }
|
|
224
268
|
[data-plugin-detail="${BUNDLE_NAME}"]:has(.capital-config-card[data-capital-config-tab="skills"]) section[data-plugin-rows] { display: none; }
|
|
225
269
|
/* Internal roles must stay declared for delegation; hide their user-selectable cards in Settings. */
|
|
226
270
|
[data-agent-preset-id="capital-data-junior"],
|
|
@@ -230,8 +274,21 @@ function installStyles() {
|
|
|
230
274
|
.capital-config-secret-row label { flex: 0 1 auto; }
|
|
231
275
|
.capital-config-secret-row label ~ span { order: 1; margin-left: auto; }
|
|
232
276
|
.capital-config-field { display: flex; flex-direction: column; gap: 6px; padding: 12px 0; border-top: 0.5px solid var(--dsw-alias-border-l2); }
|
|
277
|
+
.capital-config-automation { display: flex; flex-direction: column; gap: 16px; padding-top: 12px; }
|
|
278
|
+
.capital-config-automation-group { display: flex; flex-direction: column; gap: 8px; }
|
|
279
|
+
.capital-config-automation-group > .capital-config-group-label { color: var(--dsw-alias-label-secondary); font-size: 12px; font-weight: 500; line-height: 18px; }
|
|
280
|
+
.capital-config-number { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
|
|
281
|
+
.capital-config-workspace { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
|
|
282
|
+
.capital-config-number-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; min-width: 0; }
|
|
283
|
+
.capital-config-number-head .capital-config-write-failed { font-size: 11px; line-height: 16px; }
|
|
233
284
|
.capital-config-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 8px; }
|
|
234
|
-
.capital-config-
|
|
285
|
+
.capital-config-automation input[type="number"] { width: 100%; box-sizing: border-box; padding: 6px 8px; border: .5px solid var(--dsw-alias-border-l1); border-radius: 8px; background: var(--dsw-alias-bg-module-platform); color: var(--dsw-alias-label-primary); font: inherit; font-size: 12px; }
|
|
286
|
+
.capital-config-select { box-sizing: border-box; display: inline-flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%; min-width: 0; height: 34px; padding: 0 10px 0 12px; border: 0; border-radius: 10px; background: var(--dsw-alias-bg-module-platform); color: var(--dsw-alias-label-primary); font: inherit; font-size: 12.5px; line-height: 20px; text-align: left; cursor: pointer; transition: background .15s, opacity .15s; }
|
|
287
|
+
.capital-config-select:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
|
|
288
|
+
.capital-config-select:focus-visible { outline: 2px solid var(--dsw-focus-ring-color, var(--dsw-alias-brand-primary)); outline-offset: 0; }
|
|
289
|
+
.capital-config-select:disabled { opacity: .5; cursor: not-allowed; }
|
|
290
|
+
.capital-config-selectvalue { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
291
|
+
.capital-config-select > svg { flex: none; color: var(--dsw-alias-label-tertiary); }
|
|
235
292
|
.capital-config-selected-mode { padding: 12px 14px; border: 0.5px solid var(--dsw-alias-border-l1); border-radius: 10px; background: var(--dsw-alias-bg-layer-2); }
|
|
236
293
|
.capital-config-switch-row { align-items: center; gap: 12px; display: flex; }
|
|
237
294
|
.capital-config-switch-text { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 4px; }
|
|
@@ -290,6 +347,89 @@ function installStyles() {
|
|
|
290
347
|
return () => style.remove()
|
|
291
348
|
}
|
|
292
349
|
|
|
350
|
+
/**
|
|
351
|
+
* Dedicated workspace is the empty value, so the dropdown can keep one "follow default"
|
|
352
|
+
* entry even when the registry list is empty or the saved id has been removed.
|
|
353
|
+
*/
|
|
354
|
+
function workspaceProjection(details, rawSelected, state) {
|
|
355
|
+
const selectedId = typeof rawSelected === 'string' ? rawSelected.trim() : ''
|
|
356
|
+
const items = Array.isArray(details?.workspaces) ? details.workspaces : []
|
|
357
|
+
const dedicated = items.find((item) => item?.dedicated === true)
|
|
358
|
+
const dedicatedPath = typeof dedicated?.path === 'string' ? dedicated.path : ''
|
|
359
|
+
const options = [{
|
|
360
|
+
id: '',
|
|
361
|
+
title: typeof dedicated?.title === 'string' ? dedicated.title : '',
|
|
362
|
+
path: typeof dedicated?.displayPath === 'string' ? dedicated.displayPath : '',
|
|
363
|
+
dedicated: true,
|
|
364
|
+
missing: false,
|
|
365
|
+
}]
|
|
366
|
+
for (const item of items) {
|
|
367
|
+
if (item?.dedicated === true || (dedicatedPath !== '' && item?.path === dedicatedPath) || typeof item?.id !== 'string') continue
|
|
368
|
+
options.push({
|
|
369
|
+
id: item.id,
|
|
370
|
+
title: typeof item.title === 'string' ? item.title : item.id,
|
|
371
|
+
path: typeof item.displayPath === 'string' ? item.displayPath : '',
|
|
372
|
+
dedicated: false,
|
|
373
|
+
missing: false,
|
|
374
|
+
})
|
|
375
|
+
}
|
|
376
|
+
const missing = selectedId !== '' && !options.some((option) => option.id === selectedId)
|
|
377
|
+
if (missing) options.push({ id: selectedId, title: '', path: '', dedicated: false, missing: true })
|
|
378
|
+
const current = options.find((option) => option.id === selectedId) ?? options[0]
|
|
379
|
+
return { options, selectedId, current, missing, ...state }
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* DSH General-settings style selector: same filled pill + host `Menu` surface as the
|
|
384
|
+
* automation page. Native `<select>` is avoided so light/dark themes follow host tokens.
|
|
385
|
+
*/
|
|
386
|
+
function WorkspaceSelect({ value, options, onChange, disabled, label, describedBy }) {
|
|
387
|
+
const [open, setOpen] = useState(false)
|
|
388
|
+
const triggerRef = useRef(null)
|
|
389
|
+
const currentValue = typeof value === 'string' ? value : ''
|
|
390
|
+
const items = options.map((option) => ({
|
|
391
|
+
id: option.id === '' ? WORKSPACE_DEDICATED_MENU_ID : option.id,
|
|
392
|
+
label: option.label,
|
|
393
|
+
}))
|
|
394
|
+
const menuValue = currentValue === '' ? WORKSPACE_DEDICATED_MENU_ID : currentValue
|
|
395
|
+
const current = items.find((item) => item.id === menuValue) ?? items[0]
|
|
396
|
+
useEffect(() => {
|
|
397
|
+
if (disabled === true && open) setOpen(false)
|
|
398
|
+
}, [disabled, open])
|
|
399
|
+
const closeMenu = () => setOpen(false)
|
|
400
|
+
const selectValue = (id) => {
|
|
401
|
+
setOpen(false)
|
|
402
|
+
triggerRef.current?.focus?.({ preventScroll: true })
|
|
403
|
+
const next = id === WORKSPACE_DEDICATED_MENU_ID ? '' : id
|
|
404
|
+
if (next === currentValue) return undefined
|
|
405
|
+
return onChange(next)
|
|
406
|
+
}
|
|
407
|
+
const trigger = h('button', {
|
|
408
|
+
ref: triggerRef,
|
|
409
|
+
type: 'button',
|
|
410
|
+
className: 'capital-config-select',
|
|
411
|
+
disabled,
|
|
412
|
+
'aria-label': current?.label ? `${label}:${current.label}` : label,
|
|
413
|
+
'aria-haspopup': 'menu',
|
|
414
|
+
'aria-expanded': open ? 'true' : 'false',
|
|
415
|
+
'aria-describedby': describedBy,
|
|
416
|
+
title: current?.label,
|
|
417
|
+
onClick: () => setOpen((currentOpen) => !currentOpen),
|
|
418
|
+
},
|
|
419
|
+
h('span', { className: 'capital-config-selectvalue', title: current?.label }, current?.label ?? ''),
|
|
420
|
+
h(IconChevronDownOutlineRegular, { size: 14 }))
|
|
421
|
+
return h(Menu, {
|
|
422
|
+
open,
|
|
423
|
+
anchor: trigger,
|
|
424
|
+
items,
|
|
425
|
+
selectedId: menuValue,
|
|
426
|
+
onSelect: selectValue,
|
|
427
|
+
onClose: closeMenu,
|
|
428
|
+
align: 'start',
|
|
429
|
+
portal: true,
|
|
430
|
+
})
|
|
431
|
+
}
|
|
432
|
+
|
|
293
433
|
class CapitalCardController {
|
|
294
434
|
constructor(scope, ctx) {
|
|
295
435
|
this.scope = scope
|
|
@@ -303,6 +443,12 @@ class CapitalCardController {
|
|
|
303
443
|
this.selectedSkillsModeFailed = false
|
|
304
444
|
this.automationWriting = new Set()
|
|
305
445
|
this.automationFailed = new Set()
|
|
446
|
+
this.automationInvalid = new Set()
|
|
447
|
+
this.workspaceWriting = false
|
|
448
|
+
this.workspaceFailed = false
|
|
449
|
+
this.workspaceDetails = null
|
|
450
|
+
this.workspacesInFlight = false
|
|
451
|
+
this.workspacesFailed = false
|
|
306
452
|
// Row count is external: null = unknown, never 0; fetch only after the card is shown.
|
|
307
453
|
this.bundleRows = null
|
|
308
454
|
this.rowsRequested = false
|
|
@@ -357,7 +503,14 @@ class CapitalCardController {
|
|
|
357
503
|
on: snapshot.value?.automation?.[field] !== false,
|
|
358
504
|
writing: this.automationWriting.has(field),
|
|
359
505
|
failed: this.automationFailed.has(field),
|
|
506
|
+
invalid: this.automationInvalid.has(field),
|
|
360
507
|
}])),
|
|
508
|
+
workspace: workspaceProjection(this.workspaceDetails, snapshot.value?.automation?.[AUTOMATION_WORKSPACE_FIELD], {
|
|
509
|
+
loading: this.workspacesInFlight,
|
|
510
|
+
unavailable: this.workspacesFailed && this.workspaceDetails === null,
|
|
511
|
+
writing: this.workspaceWriting,
|
|
512
|
+
failed: this.workspaceFailed,
|
|
513
|
+
}),
|
|
361
514
|
// `count === null` means unknown, not zero: the card decides whether to draw it.
|
|
362
515
|
components: { count: this.bundleRows },
|
|
363
516
|
}
|
|
@@ -471,18 +624,34 @@ class CapitalCardController {
|
|
|
471
624
|
this.store.set(this.projection())
|
|
472
625
|
}
|
|
473
626
|
|
|
627
|
+
/** Returns why the write did or did not land: the card restores the input only for `invalid`. */
|
|
474
628
|
async writeAutomation(field, value) {
|
|
475
|
-
if (!AUTOMATION_FIELDS.includes(field) || this.automationWriting.has(field)) return
|
|
629
|
+
if (!AUTOMATION_FIELDS.includes(field) || this.automationWriting.has(field)) return 'ignored'
|
|
476
630
|
const snapshot = this.scope.getSnapshot()
|
|
477
|
-
if (snapshot.status !== 'ready' || !snapshot.writable) return
|
|
478
|
-
|
|
479
|
-
if (field
|
|
631
|
+
if (snapshot.status !== 'ready' || !snapshot.writable) return 'ignored'
|
|
632
|
+
let next
|
|
633
|
+
if (field === 'inAppNotifications') {
|
|
634
|
+
next = value === true
|
|
635
|
+
} else {
|
|
636
|
+
const { min, max } = AUTOMATION_RANGES[field]
|
|
637
|
+
const raw = typeof value === 'string' ? value.trim() : value
|
|
638
|
+
next = Number(raw)
|
|
639
|
+
if (raw === '' || raw === null || raw === undefined || !Number.isInteger(next) || next < min || next > max) {
|
|
640
|
+
// Point at the range and write nothing; the card puts the saved value back.
|
|
641
|
+
this.automationInvalid.add(field)
|
|
642
|
+
this.automationFailed.delete(field)
|
|
643
|
+
this.store.set(this.projection())
|
|
644
|
+
return 'invalid'
|
|
645
|
+
}
|
|
646
|
+
this.automationInvalid.delete(field)
|
|
647
|
+
}
|
|
480
648
|
this.automationWriting.add(field)
|
|
481
649
|
this.automationFailed.delete(field)
|
|
482
650
|
this.store.set(this.projection())
|
|
483
651
|
try {
|
|
484
|
-
|
|
485
|
-
|
|
652
|
+
// Only leaves are volatile: writing the `automation` container is rejected by the settings
|
|
653
|
+
// service even though every child field is editable.
|
|
654
|
+
await this.scope.mutate([{ op: 'set', path: ['automation', field], value: next }])
|
|
486
655
|
} catch {
|
|
487
656
|
// The landed check below reports the failure.
|
|
488
657
|
}
|
|
@@ -490,6 +659,12 @@ class CapitalCardController {
|
|
|
490
659
|
const landed = this.scope.getSnapshot().value?.automation?.[field] ?? AUTOMATION_DEFAULTS[field]
|
|
491
660
|
if (landed !== next) this.automationFailed.add(field)
|
|
492
661
|
this.store.set(this.projection())
|
|
662
|
+
return landed === next ? 'saved' : 'failed'
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
clearAutomationInvalid(field) {
|
|
666
|
+
if (!this.automationInvalid.delete(field)) return
|
|
667
|
+
this.store.set(this.projection())
|
|
493
668
|
}
|
|
494
669
|
|
|
495
670
|
/**
|
|
@@ -525,6 +700,51 @@ class CapitalCardController {
|
|
|
525
700
|
this.store.set(this.projection())
|
|
526
701
|
}
|
|
527
702
|
|
|
703
|
+
/**
|
|
704
|
+
* Workspace ids come from the automation route (same auth plane as its page), never from
|
|
705
|
+
* a path in settings. Failures are not cached: re-entering the tab retries.
|
|
706
|
+
*/
|
|
707
|
+
async ensureWorkspaces() {
|
|
708
|
+
if (this.workspaceDetails !== null || this.workspacesInFlight) return
|
|
709
|
+
this.workspacesInFlight = true
|
|
710
|
+
this.workspacesFailed = false
|
|
711
|
+
this.store.set(this.projection())
|
|
712
|
+
try {
|
|
713
|
+
if (typeof fetch !== 'function') throw new Error('fetch_unavailable')
|
|
714
|
+
const response = await fetch(WORKSPACES_ROUTE, { method: 'GET', cache: 'no-store', credentials: 'same-origin' })
|
|
715
|
+
if (!response?.ok) throw new Error(`http_${response?.status ?? 0}`)
|
|
716
|
+
const payload = await response.json()
|
|
717
|
+
if (!Array.isArray(payload?.workspaces)) throw new Error('invalid_payload')
|
|
718
|
+
this.workspaceDetails = {
|
|
719
|
+
workspaces: payload.workspaces.filter((item) => item !== null && typeof item === 'object' && typeof item.id === 'string'),
|
|
720
|
+
}
|
|
721
|
+
} catch {
|
|
722
|
+
this.workspacesFailed = true
|
|
723
|
+
}
|
|
724
|
+
this.workspacesInFlight = false
|
|
725
|
+
this.store.set(this.projection())
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
async writeAutomationWorkspace(value) {
|
|
729
|
+
if (this.workspaceWriting) return 'ignored'
|
|
730
|
+
const snapshot = this.scope.getSnapshot()
|
|
731
|
+
if (snapshot.status !== 'ready' || !snapshot.writable) return 'ignored'
|
|
732
|
+
const next = typeof value === 'string' ? value.trim() : ''
|
|
733
|
+
this.workspaceWriting = true
|
|
734
|
+
this.workspaceFailed = false
|
|
735
|
+
this.store.set(this.projection())
|
|
736
|
+
try {
|
|
737
|
+
await this.scope.mutate([{ op: 'set', path: ['automation', AUTOMATION_WORKSPACE_FIELD], value: next }])
|
|
738
|
+
} catch {
|
|
739
|
+
// The landed check below reports the failure.
|
|
740
|
+
}
|
|
741
|
+
this.workspaceWriting = false
|
|
742
|
+
const landed = (this.scope.getSnapshot().value?.automation?.[AUTOMATION_WORKSPACE_FIELD] ?? '') === next
|
|
743
|
+
if (!landed) this.workspaceFailed = true
|
|
744
|
+
this.store.set(this.projection())
|
|
745
|
+
return landed ? 'saved' : 'failed'
|
|
746
|
+
}
|
|
747
|
+
|
|
528
748
|
inject() {
|
|
529
749
|
return {
|
|
530
750
|
hooks: {
|
|
@@ -533,9 +753,12 @@ class CapitalCardController {
|
|
|
533
753
|
...this.model.actions(),
|
|
534
754
|
toggleLocalFetch: (value) => this.toggleLocalFetch(value),
|
|
535
755
|
writeAutomation: (field, value) => this.writeAutomation(field, value),
|
|
756
|
+
clearAutomationInvalid: (field) => this.clearAutomationInvalid(field),
|
|
536
757
|
toggleSelectedSkill: (field, value) => this.toggleSelectedSkill(field, value),
|
|
537
758
|
toggleSelectedSkillsMode: (auto) => this.toggleSelectedSkillsMode(auto),
|
|
538
759
|
ensureBundleRows: () => this.ensureBundleRows(),
|
|
760
|
+
ensureWorkspaces: () => this.ensureWorkspaces(),
|
|
761
|
+
writeAutomationWorkspace: (value) => this.writeAutomationWorkspace(value),
|
|
539
762
|
}
|
|
540
763
|
}
|
|
541
764
|
}
|
|
@@ -744,6 +967,10 @@ function CapitalCard(props) {
|
|
|
744
967
|
const [presetFilter, setPresetFilter] = useState(SELECTED_SKILL_FILTER_ALL)
|
|
745
968
|
// Fetch on mount: tab labels carry numbers; hooks must precede the unavailable return.
|
|
746
969
|
useEffect(() => { props.ensureBundleRows() }, [])
|
|
970
|
+
// The workspace list lives behind the automation route; fetch when its tab first opens.
|
|
971
|
+
useEffect(() => {
|
|
972
|
+
if (tab === 'automation') props.ensureWorkspaces()
|
|
973
|
+
}, [tab])
|
|
747
974
|
// Pinned order is snapshotted on tab entry so rows never move under the cursor.
|
|
748
975
|
const enabledKeys = () => new Set(SELECTED_SKILL_CATALOG
|
|
749
976
|
.filter((entry) => state.selectedSkills?.[entry.key]?.on === true)
|
|
@@ -789,37 +1016,128 @@ function CapitalCard(props) {
|
|
|
789
1016
|
),
|
|
790
1017
|
state.localFetch?.failed ? h('p', { role: 'status', className: 'capital-config-write-failed' }, t('saveFailed')) : null,
|
|
791
1018
|
)
|
|
792
|
-
const automationNumber = (field, label
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
max,
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
automationNumber('runTimeoutMinutes', 'automationRunTimeout', 5, 120),
|
|
810
|
-
automationNumber('idleTimeoutMinutes', 'automationIdleTimeout', 1, 30),
|
|
811
|
-
automationNumber('maxSteps', 'automationMaxSteps', 10, 2000),
|
|
812
|
-
automationNumber('maxToolCalls', 'automationMaxToolCalls', 10, 6000),
|
|
813
|
-
),
|
|
814
|
-
h('label', { className: 'capital-config-switch-row' },
|
|
815
|
-
h('span', { className: 'capital-config-switch-label' }, t('automationInApp')),
|
|
1019
|
+
const automationNumber = (field, label) => {
|
|
1020
|
+
const { min, max, unit } = AUTOMATION_RANGES[field]
|
|
1021
|
+
const stored = state.automation?.[field]?.value
|
|
1022
|
+
const invalid = state.automation?.[field]?.invalid === true
|
|
1023
|
+
const error = invalid
|
|
1024
|
+
? t('automationInvalid', { min, max, unit: t(unit) })
|
|
1025
|
+
: state.automation?.[field]?.failed ? t('saveFailed') : null
|
|
1026
|
+
return h('label', { className: 'capital-config-number' },
|
|
1027
|
+
// Error sits on the title row (the card's usual spot), not under the box.
|
|
1028
|
+
h('span', { className: 'capital-config-number-head' },
|
|
1029
|
+
h('span', { className: 'capital-config-switch-label' }, t(label)),
|
|
1030
|
+
error ? h('span', {
|
|
1031
|
+
id: `capital-config-automation-${field}-error`,
|
|
1032
|
+
role: invalid ? 'alert' : 'status',
|
|
1033
|
+
className: 'capital-config-write-failed',
|
|
1034
|
+
}, error) : null,
|
|
1035
|
+
),
|
|
816
1036
|
h('input', {
|
|
817
|
-
type: '
|
|
818
|
-
|
|
1037
|
+
type: 'number',
|
|
1038
|
+
min,
|
|
1039
|
+
max,
|
|
1040
|
+
step: 1,
|
|
1041
|
+
defaultValue: stored,
|
|
819
1042
|
disabled: disabled || state.saving,
|
|
820
|
-
|
|
1043
|
+
'aria-invalid': invalid ? 'true' : undefined,
|
|
1044
|
+
'aria-describedby': error ? `capital-config-automation-${field}-error` : undefined,
|
|
1045
|
+
onFocus: () => props.clearAutomationInvalid(field),
|
|
1046
|
+
onBlur: (event) => {
|
|
1047
|
+
const input = event.target
|
|
1048
|
+
return Promise.resolve(props.writeAutomation(field, input.value)).then((outcome) => {
|
|
1049
|
+
if (outcome === 'invalid' && stored !== undefined) input.value = String(stored)
|
|
1050
|
+
})
|
|
1051
|
+
},
|
|
821
1052
|
}),
|
|
1053
|
+
)
|
|
1054
|
+
}
|
|
1055
|
+
const automationGroup = (labelKey, children) => h('div', { className: 'capital-config-automation-group' },
|
|
1056
|
+
h('span', { className: 'capital-config-group-label' }, t(labelKey)),
|
|
1057
|
+
...children,
|
|
1058
|
+
)
|
|
1059
|
+
const workspaceState = state.workspace ?? {
|
|
1060
|
+
options: [],
|
|
1061
|
+
selectedId: '',
|
|
1062
|
+
current: null,
|
|
1063
|
+
missing: false,
|
|
1064
|
+
loading: false,
|
|
1065
|
+
unavailable: false,
|
|
1066
|
+
writing: false,
|
|
1067
|
+
failed: false,
|
|
1068
|
+
}
|
|
1069
|
+
const workspacePathId = 'capital-config-automation-workspace-path'
|
|
1070
|
+
const namedWorkspaceOptions = workspaceState.options.map((option) => ({
|
|
1071
|
+
id: option.id,
|
|
1072
|
+
path: option.path,
|
|
1073
|
+
label: option.id === ''
|
|
1074
|
+
? (option.title || t('automationWorkspaceFallback'))
|
|
1075
|
+
: option.missing ? t('automationWorkspaceMissing') : option.title,
|
|
1076
|
+
}))
|
|
1077
|
+
const workspaceLabelCounts = new Map()
|
|
1078
|
+
for (const option of namedWorkspaceOptions) {
|
|
1079
|
+
workspaceLabelCounts.set(option.label, (workspaceLabelCounts.get(option.label) ?? 0) + 1)
|
|
1080
|
+
}
|
|
1081
|
+
const workspaceOptions = namedWorkspaceOptions.map((option) => {
|
|
1082
|
+
if (option.id === '' || !option.path || (workspaceLabelCounts.get(option.label) ?? 0) < 2) return option
|
|
1083
|
+
// Two registered workspaces may legitimately share a title; path keeps the menu unambiguous.
|
|
1084
|
+
return { ...option, label: `${option.label} · ${option.path}` }
|
|
1085
|
+
})
|
|
1086
|
+
const workspaceSection = h('div', { className: 'capital-config-workspace' },
|
|
1087
|
+
h('span', { className: 'capital-config-number-head' },
|
|
1088
|
+
h('span', { className: 'capital-config-switch-label' }, t('automationDefaultWorkspace')),
|
|
1089
|
+
workspaceState.failed
|
|
1090
|
+
? h('span', { role: 'status', className: 'capital-config-write-failed' }, t('saveFailed'))
|
|
1091
|
+
: null,
|
|
822
1092
|
),
|
|
1093
|
+
h(WorkspaceSelect, {
|
|
1094
|
+
value: workspaceState.selectedId,
|
|
1095
|
+
options: workspaceOptions,
|
|
1096
|
+
onChange: (next) => props.writeAutomationWorkspace(next),
|
|
1097
|
+
disabled: disabled || state.saving || workspaceState.writing,
|
|
1098
|
+
label: t('automationDefaultWorkspace'),
|
|
1099
|
+
describedBy: workspaceState.current?.path ? workspacePathId : undefined,
|
|
1100
|
+
}),
|
|
1101
|
+
workspaceState.unavailable
|
|
1102
|
+
? h('p', { role: 'status', className: 'capital-config-hint' }, t('automationWorkspaceUnavailable'))
|
|
1103
|
+
: workspaceState.loading
|
|
1104
|
+
? h('p', { className: 'capital-config-hint' }, t('automationWorkspaceLoading'))
|
|
1105
|
+
: workspaceState.missing
|
|
1106
|
+
? h('p', { role: 'status', className: 'capital-config-write-failed' }, t('automationWorkspaceMissing'))
|
|
1107
|
+
: workspaceState.current?.path
|
|
1108
|
+
? h('p', { id: workspacePathId, className: 'capital-config-hint' }, t('automationWorkspacePath', { path: workspaceState.current.path }))
|
|
1109
|
+
: null,
|
|
1110
|
+
)
|
|
1111
|
+
const automationSection = h('div', { className: 'capital-config-automation' },
|
|
1112
|
+
workspaceSection,
|
|
1113
|
+
automationGroup('automationScheduleGroup', [
|
|
1114
|
+
h('div', { className: 'capital-config-grid' },
|
|
1115
|
+
automationNumber('tickMs', 'automationTick'),
|
|
1116
|
+
),
|
|
1117
|
+
]),
|
|
1118
|
+
automationGroup('automationRunGroup', [
|
|
1119
|
+
h('div', { className: 'capital-config-grid' },
|
|
1120
|
+
automationNumber('runTimeoutMinutes', 'automationRunTimeout'),
|
|
1121
|
+
automationNumber('idleTimeoutMinutes', 'automationIdleTimeout'),
|
|
1122
|
+
automationNumber('maxSteps', 'automationMaxSteps'),
|
|
1123
|
+
automationNumber('maxToolCalls', 'automationMaxToolCalls'),
|
|
1124
|
+
),
|
|
1125
|
+
]),
|
|
1126
|
+
automationGroup('automationNotifyGroup', [
|
|
1127
|
+
h('div', { className: 'capital-config-switch-row' },
|
|
1128
|
+
h('div', { className: 'capital-config-switch-text' },
|
|
1129
|
+
h('span', { className: 'capital-config-switch-label' }, t('automationInApp')),
|
|
1130
|
+
h('p', { className: 'capital-config-hint' }, t('automationInAppHint')),
|
|
1131
|
+
),
|
|
1132
|
+
h(Switch, {
|
|
1133
|
+
label: t('automationInApp'),
|
|
1134
|
+
checked: state.automation?.inAppNotifications?.on !== false,
|
|
1135
|
+
disabled: disabled || state.saving || state.automation?.inAppNotifications?.writing === true,
|
|
1136
|
+
onChange: (value) => props.writeAutomation('inAppNotifications', value),
|
|
1137
|
+
}),
|
|
1138
|
+
),
|
|
1139
|
+
state.automation?.inAppNotifications?.failed ? h('p', { role: 'status', className: 'capital-config-write-failed' }, t('saveFailed')) : null,
|
|
1140
|
+
]),
|
|
823
1141
|
)
|
|
824
1142
|
const modeSection = h('div', { className: 'capital-config-selected-mode' },
|
|
825
1143
|
h('div', { className: 'capital-config-switch-row' },
|
|
@@ -889,6 +1207,7 @@ function CapitalCard(props) {
|
|
|
889
1207
|
const options = [
|
|
890
1208
|
// A dirty draft while Save is off-screen must be announced on the tab.
|
|
891
1209
|
{ value: 'sources', label: state.dirty ? t('titleUnsaved') : t('title') },
|
|
1210
|
+
{ value: 'automation', label: t('automationTitle') },
|
|
892
1211
|
{ value: 'skills', label: t('selectedSkillsTitle') },
|
|
893
1212
|
{ value: 'components', label: withCount(t('componentsTitle'), state.components?.count) },
|
|
894
1213
|
]
|
|
@@ -911,11 +1230,13 @@ function CapitalCard(props) {
|
|
|
911
1230
|
setTab(next)
|
|
912
1231
|
// Re-read on every switch to this tab: a previous failure retries here.
|
|
913
1232
|
if (next === 'components') props.ensureBundleRows()
|
|
1233
|
+
if (next === 'automation') props.ensureWorkspaces()
|
|
914
1234
|
// Re-pin only when entering Skills, so the row under the cursor never jumps.
|
|
915
1235
|
if (next === 'skills') setPinnedSkills(enabledKeys())
|
|
916
1236
|
},
|
|
917
1237
|
}),
|
|
918
|
-
panel('sources', [form, localFetchSection
|
|
1238
|
+
panel('sources', [form, localFetchSection]),
|
|
1239
|
+
panel('automation', [automationSection]),
|
|
919
1240
|
panel('skills', autoMode
|
|
920
1241
|
? [modeSection]
|
|
921
1242
|
: [modeSection, h('div', { className: 'capital-config-skills-browser' },
|
package/config/index.js
CHANGED
|
@@ -77,19 +77,21 @@ export const Config = z.object({
|
|
|
77
77
|
fuyaoCredentialRef: z.string().default('FUYAO_API_KEY').volatile().description('Fuyao credentials 引用名'),
|
|
78
78
|
ftshareCredentialRef: z.string().default('FTSHARE_API_KEY').volatile().description('FTShare(非凸科技)credentials 引用名'),
|
|
79
79
|
automation: z.object({
|
|
80
|
-
tickMs: z.number().default(60_000).volatile().description('
|
|
81
|
-
runTimeoutMinutes: z.number().default(
|
|
80
|
+
tickMs: z.number().default(60_000).volatile().description('投研自动化自动检查间隔(毫秒,30000–3600000)'),
|
|
81
|
+
runTimeoutMinutes: z.number().default(60).volatile().description('单次运行最长运行时间(分钟,5–120)'),
|
|
82
82
|
idleTimeoutMinutes: z.number().default(5).volatile().description('单次运行空闲超时分钟(1–30)'),
|
|
83
|
-
maxSteps: z.number().default(300).volatile().description('单次运行最大步骤数(
|
|
84
|
-
maxToolCalls: z.number().default(1_200).volatile().description('单次运行最大工具调用数(
|
|
83
|
+
maxSteps: z.number().default(300).volatile().description('单次运行最大步骤数(100–2000)'),
|
|
84
|
+
maxToolCalls: z.number().default(1_200).volatile().description('单次运行最大工具调用数(100–5000)'),
|
|
85
85
|
inAppNotifications: z.boolean().default(true).volatile().description('是否写入应用内通知'),
|
|
86
|
+
defaultWorkspaceId: z.string().default('').volatile().description('统一默认工作区 id;空 = 专属默认工作区'),
|
|
86
87
|
}).default({
|
|
87
88
|
tickMs: 60_000,
|
|
88
|
-
runTimeoutMinutes:
|
|
89
|
+
runTimeoutMinutes: 60,
|
|
89
90
|
idleTimeoutMinutes: 5,
|
|
90
91
|
maxSteps: 300,
|
|
91
92
|
maxToolCalls: 1_200,
|
|
92
93
|
inAppNotifications: true,
|
|
94
|
+
defaultWorkspaceId: '',
|
|
93
95
|
}).description('投研自动化默认值;任务级覆盖优先'),
|
|
94
96
|
retriever: z.object({
|
|
95
97
|
baseURL: z.string().default('').volatile().description('AnySearch API 地址'),
|
package/config/package.json
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Root Agent tool convergence on the root's own scope: preset-level deny would also hit
|
|
3
3
|
* children. Listeners must live on `ctx.root`; tagged standing-scope listeners miss agent/created.
|
|
4
4
|
*/
|
|
5
|
-
/** Outbound tools (search 2 + wind 2 + named sources
|
|
6
|
-
export declare const RETRIEVAL_DENIED_TOOLS: readonly ["anysearch_search", "web_retriever_fetch", "wind_docs_announcements", "wind_docs_news", "cls_telegraph", "wscn_lives", "cninfo_irm", "sseinfo_qa", "eastmoney_724", "eastmoney_stock_news", "eastmoney_reports", "sina_reports", "ths_eps_forecast"];
|
|
5
|
+
/** Outbound tools (search 2 + wind 2 + named sources 11); `ocr` is excluded because only its url form is restricted. */
|
|
6
|
+
export declare const RETRIEVAL_DENIED_TOOLS: readonly ["anysearch_search", "web_retriever_fetch", "wind_docs_announcements", "wind_docs_news", "cls_telegraph", "wscn_lives", "cninfo_irm", "sseinfo_qa", "eastmoney_724", "eastmoney_stock_news", "eastmoney_reports", "eastmoney_announcements", "eastmoney_announcement_body", "sina_reports", "ths_eps_forecast"];
|
|
7
7
|
export declare const OCR_TOOL_NAME = "ocr";
|
|
8
8
|
/** Name-level deny cannot express the form distinction; this is a call-level guard. */
|
|
9
9
|
export declare const OCR_ROOT_URL_DENIED: string;
|
|
@@ -12,7 +12,7 @@ export declare function ocrUrlFormRequested(exec: GuardedExecution | undefined):
|
|
|
12
12
|
export declare function ocrFormGuardReasonFor(ctx: PolicyContext): (exec: GuardedExecution | undefined) => string | undefined;
|
|
13
13
|
/** Mounted as a platform pair; recognize both everywhere or the other platform's gate is dead. */
|
|
14
14
|
export declare const SHELL_TOOL_NAMES: readonly ["bash", "pwsh"];
|
|
15
|
-
export declare const ROOT_AGENT_DENIED_TOOLS: readonly ["render_chart", "prepare_chart_source", "anysearch_search", "web_retriever_fetch", "wind_docs_announcements", "wind_docs_news", "cls_telegraph", "wscn_lives", "cninfo_irm", "sseinfo_qa", "eastmoney_724", "eastmoney_stock_news", "eastmoney_reports", "sina_reports", "ths_eps_forecast", "write", "edit"];
|
|
15
|
+
export declare const ROOT_AGENT_DENIED_TOOLS: readonly ["render_chart", "prepare_chart_source", "anysearch_search", "web_retriever_fetch", "wind_docs_announcements", "wind_docs_news", "cls_telegraph", "wscn_lives", "cninfo_irm", "sseinfo_qa", "eastmoney_724", "eastmoney_stock_news", "eastmoney_reports", "eastmoney_announcements", "eastmoney_announcement_body", "sina_reports", "ths_eps_forecast", "write", "edit"];
|
|
16
16
|
export declare const CAPITAL_PRESET_ID = "capital-generation";
|
|
17
17
|
interface ToolRestriction {
|
|
18
18
|
allow?: readonly string[];
|