dsh-bots 0.2.27 → 0.2.28
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/lib/client.js +34 -17
- package/lib/index.js +17 -1
- package/lib/types/index.d.ts +1 -0
- package/lib/types/shared.d.ts +3 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -484,7 +484,7 @@
|
|
|
484
484
|
'chat.stop.noop': '当前没有进行中的生成',
|
|
485
485
|
'media.openFailed': '打开失败,文件可能已移动或被删除',
|
|
486
486
|
'chat.members.manage': '管理成员',
|
|
487
|
-
'chat.members.cap': '已达群成员上限 {cap}
|
|
487
|
+
'chat.members.cap': '已达群成员上限 {cap} 人——可在会话设置里调高',
|
|
488
488
|
'chat.settings': '设置',
|
|
489
489
|
'chat.settings.title': '会话设置',
|
|
490
490
|
'chat.settings.name': '名称',
|
|
@@ -495,9 +495,11 @@
|
|
|
495
495
|
'chat.settings.paths': '额外可写路径(逗号分隔)',
|
|
496
496
|
'chat.settings.pathsPh': '/tmp/xxx, /Users/you/shared',
|
|
497
497
|
'chat.settings.hint': '写入被沙盒限制在工作区(含额外路径)内,读取不受限;同 slug 的 Bot 共享同一目录。',
|
|
498
|
+
'chat.settings.cap': '成员上限(1–16)',
|
|
499
|
+
'chat.settings.capHint': '保存在该群的配置里;调低会立即截断超出部分。',
|
|
500
|
+
'chat.settings.capBad': '成员上限需为 1–16 的整数',
|
|
498
501
|
'modal.members.title': '管理群成员',
|
|
499
502
|
'modal.members.hint': '勾选的 Bot 为群成员;保存后立即生效(可随时再改)。',
|
|
500
|
-
'modal.members.cap': '成员上限(1–16)',
|
|
501
503
|
'action.delete': '删除',
|
|
502
504
|
'delete.title.bot': '删除 Bot',
|
|
503
505
|
'delete.title.group': '删除群聊',
|
|
@@ -600,7 +602,7 @@
|
|
|
600
602
|
'chat.stop.noop': 'No generation in progress',
|
|
601
603
|
'media.openFailed': 'Open failed — the file may have moved or been deleted',
|
|
602
604
|
'chat.members.manage': 'Manage members',
|
|
603
|
-
'chat.members.cap': 'Group cap is {cap} members — raise
|
|
605
|
+
'chat.members.cap': 'Group cap is {cap} members — raise it in session settings',
|
|
604
606
|
'chat.settings': 'Settings',
|
|
605
607
|
'chat.settings.title': 'Session settings',
|
|
606
608
|
'chat.settings.name': 'Name',
|
|
@@ -611,9 +613,11 @@
|
|
|
611
613
|
'chat.settings.paths': 'Extra writable paths (comma-separated)',
|
|
612
614
|
'chat.settings.pathsPh': '/tmp/xxx, /Users/you/shared',
|
|
613
615
|
'chat.settings.hint': 'Writes are sandboxed to the workspace (plus extra paths); reads stay unrestricted. Bots sharing a slug share one directory.',
|
|
616
|
+
'chat.settings.cap': 'Member cap (1–16)',
|
|
617
|
+
'chat.settings.capHint': 'Stored in this group\'s config; lowering it drops members beyond the new cap right away.',
|
|
618
|
+
'chat.settings.capBad': 'The cap must be an integer from 1 to 16',
|
|
614
619
|
'modal.members.title': 'Manage group members',
|
|
615
620
|
'modal.members.hint': 'Checked bots are members; changes apply immediately on save (editable again anytime).',
|
|
616
|
-
'modal.members.cap': 'Member cap (1–16)',
|
|
617
621
|
'action.delete': 'Delete',
|
|
618
622
|
'delete.title.bot': 'Delete bot',
|
|
619
623
|
'delete.title.group': 'Delete group chat',
|
|
@@ -2224,7 +2228,6 @@
|
|
|
2224
2228
|
const [picked, setPicked] = React.useState(null);
|
|
2225
2229
|
const [err, setErr] = React.useState(null);
|
|
2226
2230
|
const [working, setWorking] = React.useState(false);
|
|
2227
|
-
const [capText, setCapText] = React.useState('8');
|
|
2228
2231
|
// Seed once per opened group; a group vanishing mid-edit (deleted by
|
|
2229
2232
|
// the swarm, say) just renders the modal inert until closed.
|
|
2230
2233
|
React.useEffect(() => {
|
|
@@ -2234,18 +2237,17 @@
|
|
|
2234
2237
|
for (const id of group.memberIds ?? [])
|
|
2235
2238
|
init[id] = true;
|
|
2236
2239
|
setPicked(init);
|
|
2237
|
-
setCapText(String(group.maxMembers ?? 8));
|
|
2238
2240
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2239
2241
|
}, [s.manageMembers]);
|
|
2240
2242
|
if (group === null || group === undefined)
|
|
2241
2243
|
return null;
|
|
2242
2244
|
const singles = s.agents.filter((a) => !a.isGroup && a.isHiddenFromSidebar !== true);
|
|
2243
2245
|
const pickedIds = picked === null ? [] : Object.keys(picked).filter((k) => picked[k]);
|
|
2244
|
-
// Per-group cap (group.json maxMembers, default 8, engine hard max 16
|
|
2245
|
-
// the
|
|
2246
|
-
//
|
|
2247
|
-
//
|
|
2248
|
-
const MEMBER_CAP =
|
|
2246
|
+
// Per-group cap (group.json maxMembers, default 8, engine hard max 16;
|
|
2247
|
+
// the host enriches group rows with the real value). The glue slice(0,
|
|
2248
|
+
// maxMembers)-truncates the roster SILENTLY, so an over-cap pick is
|
|
2249
|
+
// blocked here — the cap itself is edited in session settings.
|
|
2250
|
+
const MEMBER_CAP = group.maxMembers ?? 8;
|
|
2249
2251
|
const overCap = pickedIds.length > MEMBER_CAP;
|
|
2250
2252
|
function toggle(id) {
|
|
2251
2253
|
if (picked === null)
|
|
@@ -2263,7 +2265,7 @@
|
|
|
2263
2265
|
setWorking(true);
|
|
2264
2266
|
setErr(null);
|
|
2265
2267
|
try {
|
|
2266
|
-
await botsCall('setGroupMembers', { id: group.id, memberIds: pickedIds
|
|
2268
|
+
await botsCall('setGroupMembers', { id: group.id, memberIds: pickedIds });
|
|
2267
2269
|
patch({ manageMembers: null });
|
|
2268
2270
|
await refreshAgents();
|
|
2269
2271
|
return;
|
|
@@ -2286,10 +2288,7 @@
|
|
|
2286
2288
|
disabled: working,
|
|
2287
2289
|
icon: Ico('IconCloseOutline16', { size: 16 }),
|
|
2288
2290
|
onClick: () => patch({ manageMembers: null }),
|
|
2289
|
-
})), e('div', { className: 'dbs-modalBody' }, e('div', { className: 'dbs-meta', style: { padding: '0 2px 6px' } }, t('modal.members.hint')),
|
|
2290
|
-
value: capText, disabled: working, style: { width: 72 },
|
|
2291
|
-
onChange: (ev) => setCapText(ev.target.value),
|
|
2292
|
-
})), picked === null
|
|
2291
|
+
})), e('div', { className: 'dbs-modalBody' }, e('div', { className: 'dbs-meta', style: { padding: '0 2px 6px' } }, t('modal.members.hint')), picked === null
|
|
2293
2292
|
? e('div', { className: 'dbs-meta', style: { padding: '4px 6px' } }, t('list.loading'))
|
|
2294
2293
|
: e('div', { className: 'dbs-modalMembers' }, singles.length === 0
|
|
2295
2294
|
? e('div', { className: 'dbs-meta', style: { padding: '4px 6px' } }, t('list.empty'))
|
|
@@ -2328,11 +2327,13 @@
|
|
|
2328
2327
|
const [wsLoaded, setWsLoaded] = React.useState(false);
|
|
2329
2328
|
const [working, setWorking] = React.useState(false);
|
|
2330
2329
|
const [err, setErr] = React.useState(null);
|
|
2330
|
+
const [capText, setCapText] = React.useState('8');
|
|
2331
2331
|
React.useEffect(() => {
|
|
2332
2332
|
if (agent === null || agent === undefined)
|
|
2333
2333
|
return;
|
|
2334
2334
|
setName(String(agent.name ?? ''));
|
|
2335
2335
|
setDesc(String(agent.description ?? ''));
|
|
2336
|
+
setCapText(String(agent.maxMembers ?? 8));
|
|
2336
2337
|
if (agent.isGroup === true) {
|
|
2337
2338
|
setWsLoaded(true);
|
|
2338
2339
|
return;
|
|
@@ -2354,13 +2355,24 @@
|
|
|
2354
2355
|
if (agent === null || agent === undefined)
|
|
2355
2356
|
return null;
|
|
2356
2357
|
const valid = name.trim() !== '';
|
|
2358
|
+
// Member cap lives here (session settings), not in the roster editor:
|
|
2359
|
+
// it is this group's own config field. Empty/unchanged = keep.
|
|
2360
|
+
const capNum = Math.floor(Number(capText));
|
|
2361
|
+
const capValid = capText.trim() === '' || (Number.isInteger(capNum) && capNum >= 1 && capNum <= 16);
|
|
2357
2362
|
async function save() {
|
|
2358
2363
|
if (working || valid === false)
|
|
2359
2364
|
return;
|
|
2365
|
+
if (capValid === false) {
|
|
2366
|
+
setErr(t('chat.settings.capBad'));
|
|
2367
|
+
return;
|
|
2368
|
+
}
|
|
2360
2369
|
setWorking(true);
|
|
2361
2370
|
setErr(null);
|
|
2362
2371
|
try {
|
|
2363
2372
|
await botsCall('update', { id: agent.id, profile: { name: name.trim(), description: desc.trim() } });
|
|
2373
|
+
if (agent.isGroup === true && capText.trim() !== '') {
|
|
2374
|
+
await botsCall('setGroupMembers', { id: agent.id, memberIds: agent.memberIds ?? [], maxMembers: capNum });
|
|
2375
|
+
}
|
|
2364
2376
|
if (agent.isGroup !== true && wsLoaded === true) {
|
|
2365
2377
|
const list = paths.split(/[,,]/).map((x) => x.trim()).filter((x) => x !== '');
|
|
2366
2378
|
await botsCall('workspaceSet', {
|
|
@@ -2394,7 +2406,12 @@
|
|
|
2394
2406
|
})), e('div', { className: 'dbs-modalBody' }, e('div', { className: 'dbs-setLabel' }, t('chat.settings.name')), e(Input, {
|
|
2395
2407
|
value: name, autoFocus: true, disabled: working,
|
|
2396
2408
|
onChange: (ev) => setName(ev.target.value),
|
|
2397
|
-
}), isGroup ===
|
|
2409
|
+
}), isGroup === true
|
|
2410
|
+
? e('div', null, e('div', { className: 'dbs-setLabel' }, t('chat.settings.cap')), e(Input, {
|
|
2411
|
+
value: capText, disabled: working, inputMode: 'numeric', style: { width: 96 },
|
|
2412
|
+
onChange: (ev) => setCapText(ev.target.value),
|
|
2413
|
+
}), e('div', { className: 'dbs-meta', style: { marginTop: 6 } }, t('chat.settings.capHint')))
|
|
2414
|
+
: null, isGroup === false
|
|
2398
2415
|
? e('div', null, e('div', { className: 'dbs-setLabel' }, t('chat.settings.desc')), e(Input, {
|
|
2399
2416
|
value: desc, disabled: working,
|
|
2400
2417
|
onChange: (ev) => setDesc(ev.target.value),
|
package/lib/index.js
CHANGED
|
@@ -214,7 +214,22 @@ export class BotsRemote extends TypertRemoteService {
|
|
|
214
214
|
* would make the gateway reject the envelope with "unexpected request".
|
|
215
215
|
*/
|
|
216
216
|
async list(request) {
|
|
217
|
-
|
|
217
|
+
const agents = normalizeAgents(await callGateway(this.cfg.dataDir, 'listAgents', {}));
|
|
218
|
+
// The gateway row omits group.json's maxMembers, so read it here — the
|
|
219
|
+
// settings editor needs the CURRENT cap, not a hardcoded default.
|
|
220
|
+
for (const a of agents) {
|
|
221
|
+
if (a.isGroup !== true)
|
|
222
|
+
continue;
|
|
223
|
+
try {
|
|
224
|
+
const cfg = JSON.parse(readFileSync(join(effectiveDataDir(this.cfg.dataDir), 'agents', a.id, 'group.json'), 'utf-8'));
|
|
225
|
+
const n = typeof cfg.maxMembers === 'number' ? Math.floor(cfg.maxMembers) : Number.NaN;
|
|
226
|
+
a.maxMembers = Number.isFinite(n) ? Math.min(16, Math.max(1, n)) : 8;
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
a.maxMembers = 8;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return agents;
|
|
218
233
|
}
|
|
219
234
|
async workspaces(request) {
|
|
220
235
|
const registry = this.ctx.get('workspaceRegistry');
|
|
@@ -285,6 +300,7 @@ export class BotsRemote extends TypertRemoteService {
|
|
|
285
300
|
const updated = await callGateway(this.cfg.dataDir, 'setGroupMembers', {
|
|
286
301
|
id: request?.id,
|
|
287
302
|
memberAgentIds: Array.isArray(request?.memberIds) ? request.memberIds : [],
|
|
303
|
+
...(typeof request?.maxMembers === 'number' ? { maxMembers: request.maxMembers } : {}),
|
|
288
304
|
});
|
|
289
305
|
return trimAgent(updated?.agent ?? updated);
|
|
290
306
|
}
|
package/lib/types/index.d.ts
CHANGED
|
@@ -91,6 +91,7 @@ export declare class BotsRemote extends TypertRemoteService {
|
|
|
91
91
|
setGroupMembers(request: {
|
|
92
92
|
id?: string;
|
|
93
93
|
memberIds?: string[];
|
|
94
|
+
maxMembers?: number;
|
|
94
95
|
} | null): Promise<AgentInfo | null>;
|
|
95
96
|
/**
|
|
96
97
|
* Resolve a bot-written path against the media allowlist: only files inside
|
package/lib/types/shared.d.ts
CHANGED
|
@@ -20,6 +20,9 @@ export interface AgentInfo {
|
|
|
20
20
|
title: string;
|
|
21
21
|
isGroup: boolean;
|
|
22
22
|
memberIds: string[];
|
|
23
|
+
/** Per-group roster cap (group.json maxMembers; 1-16, default 8). The
|
|
24
|
+
gateway row omits it, so the host enriches group rows from disk. */
|
|
25
|
+
maxMembers?: number;
|
|
23
26
|
isRunning: boolean;
|
|
24
27
|
isActive: boolean;
|
|
25
28
|
lastMessagePreview: string | null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-bots",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.28",
|
|
4
4
|
"description": "Multi-bot workbench for DeepSeek Harness: bridges the sdk-bots orchestration gateway (group chats, single bots) into the dsh web shell with official-styled UI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|