cs-bots 0.1.0 → 0.7.4
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 +533 -0
- package/README.md +65 -10
- package/docs/01-/346/236/266/346/236/204/346/226/207/346/241/243.md +364 -0
- package/docs/02-/351/234/200/346/261/202/350/247/204/346/240/274/344/271/246.md +284 -0
- package/docs/03-/350/257/246/347/273/206/350/256/276/350/256/241.md +567 -0
- package/docs/04-/346/223/215/344/275/234/346/211/213/345/206/214.md +569 -0
- package/docs/ARCHITECTURE.md +277 -0
- package/docs/adr/ADR-001-/351/241/265/347/255/276/347/273/223/346/236/204/345/233/236/345/210/260/344/270/203/351/241/265.md +70 -0
- package/docs/steps/step-01-/345/216/237/346/236/266/346/236/204/345/244/215/345/216/237/344/270/216IA/350/257/212/346/226/255.md +80 -0
- package/docs/steps/step-02-/351/241/265/347/255/276/346/224/266/346/225/233/344/270/216/345/215/207/347/272/247/351/200/232/351/201/223.md +51 -0
- package/docs/steps/step-03-/346/236/266/346/236/204/350/265/204/346/226/231/346/210/220/346/226/207.md +16 -0
- package/docs/steps/step-04-/344/270/212/347/272/277/344/270/216/351/252/214/350/257/201.md +46 -0
- package/docs//344/272/244/344/273/230/350/257/264/346/230/216-v0.2.0.md +95 -0
- package/docs//346/223/215/344/275/234/346/211/213/345/206/214-v1.md +509 -0
- package/docs//350/277/201/347/247/273/346/226/271/346/241/210-v1.md +64 -0
- package/docs//351/225/277/346/234/237/350/256/260/345/277/206/346/226/271/346/241/210-v1.md +85 -0
- package/package.json +4 -2
- package/src/admission.js +365 -0
- package/src/api.js +4097 -420
- package/src/board.js +883 -14
- package/src/botprofile.js +190 -3
- package/src/client.js +6596 -1082
- package/src/cycle.js +516 -0
- package/src/delivery-watch.js +255 -0
- package/src/dirbrowse.js +20 -0
- package/src/discipline.js +1188 -0
- package/src/fence.js +142 -0
- package/src/index.js +387 -4
- package/src/kernel.js +636 -24
- package/src/library.js +1224 -11
- package/src/memory.js +617 -37
- package/src/metrics.js +339 -0
- package/src/prompts.js +1318 -0
- package/src/reviewer.js +709 -0
- package/src/room.js +655 -14
- package/src/roster.js +346 -26
- package/src/routing/complexity.js +320 -0
- package/src/routing/hints.js +707 -0
- package/src/scratch.js +477 -0
- package/src/settings.js +97 -0
- package/src/stage.js +263 -0
- package/src/store.js +133 -1
- package/src/subscription.js +571 -0
- package/src/suggest.js +1203 -0
- package/src/teams.js +527 -0
- package/src/todo.js +1301 -0
- package/src/tools.js +734 -10
- package/src/verify.js +356 -0
package/src/tools.js
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import { registerTool } from './kernel.js'
|
|
16
16
|
import { getServices } from './registry.js'
|
|
17
|
+
import { applyTaskHint } from './routing/hints.js'
|
|
17
18
|
|
|
18
19
|
/** 统一的失败构造(所有工具都返回它,绝不抛出去让宿主崩)。 */
|
|
19
20
|
function failure(reason, extra = {}) {
|
|
@@ -28,7 +29,8 @@ function success(payload) {
|
|
|
28
29
|
/**
|
|
29
30
|
* 从宿主上下文取本平台的域服务。
|
|
30
31
|
* @param {object} ctx
|
|
31
|
-
* @returns {{ board?: object, roster?: object, room?: object, memory?: object, dispatcher?: object
|
|
32
|
+
* @returns {{ board?: object, roster?: object, room?: object, memory?: object, dispatcher?: object,
|
|
33
|
+
* todo?: object, scratch?: object, prompts?: object, discipline?: object, suggest?: object }}
|
|
32
34
|
*/
|
|
33
35
|
function servicesOf(ctx) {
|
|
34
36
|
return getServices(ctx)
|
|
@@ -39,6 +41,33 @@ function callerOf(exec) {
|
|
|
39
41
|
return exec?.agent?.id ?? exec?.agent?.session?.id ?? 'unknown'
|
|
40
42
|
}
|
|
41
43
|
|
|
44
|
+
/** 从唤醒去重键反推任务 id:`task-assigned:t-3` / `task-unblocked:t-3` / `tasks-assigned:t-3`。 */
|
|
45
|
+
function taskIdFromDedup(dedupKey) {
|
|
46
|
+
if (typeof dedupKey !== 'string') return undefined
|
|
47
|
+
const m = /^tasks?-(?:assigned|unblocked):(t-\d+)$/.exec(dedupKey.trim())
|
|
48
|
+
return m ? m[1] : undefined
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 用任务字段给某个会话写路由 hint(缺任务/缺会话/缺 cs-myfree 都返回 `undefined`,
|
|
53
|
+
* 唤醒本身**照样要发出去** —— hint 只是优化)。
|
|
54
|
+
*
|
|
55
|
+
* @param {object|undefined} board
|
|
56
|
+
* @param {string} taskId
|
|
57
|
+
* @param {string} sessionId
|
|
58
|
+
* @returns {{ ok: boolean, hint?: object, reason?: string } | undefined}
|
|
59
|
+
*/
|
|
60
|
+
function hintForTask(board, taskId, sessionId) {
|
|
61
|
+
if (!board || typeof board.get !== 'function') return undefined
|
|
62
|
+
try {
|
|
63
|
+
const task = board.get(taskId)
|
|
64
|
+
if (!task) return undefined
|
|
65
|
+
return applyTaskHint(task, sessionId, { role: 'subagent' })
|
|
66
|
+
} catch {
|
|
67
|
+
return undefined
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
42
71
|
// ── 工具定义表 ───────────────────────────────────────────────────────────────
|
|
43
72
|
//
|
|
44
73
|
// 每个条目:{ name, description, parameters, run(services, args, exec) }
|
|
@@ -49,7 +78,11 @@ const DEFS = [
|
|
|
49
78
|
{
|
|
50
79
|
name: 'bot_task_create',
|
|
51
80
|
description:
|
|
52
|
-
'在 cs-bots 跨会话任务板上创建一个任务。返回任务 id 与 rev;后续用 bot_task_update 推进状态(CAS 需带 expectedRev)。'
|
|
81
|
+
'在 cs-bots 跨会话任务板上创建一个任务。返回任务 id 与 rev;后续用 bot_task_update 推进状态(CAS 需带 expectedRev)。' +
|
|
82
|
+
'【复杂度路由】规划 Agent 拆解任务时**必须**给每个子任务显式标注 expectedComplexity(即 expected_complexity,' +
|
|
83
|
+
'T0 简单 / T1 常规 / T2 较难 / T3 很难):子智能体默认 free_only(只走免费渠道),**只有** requiresPaid=true ' +
|
|
84
|
+
'(即 requires_paid:true)的子任务才获 paid_allowed。拿不准就给低档 + 不标 requiresPaid —— ' +
|
|
85
|
+
'误判为免费只是慢,误判为付费是浪费钱。',
|
|
53
86
|
parameters: {
|
|
54
87
|
type: 'object',
|
|
55
88
|
properties: {
|
|
@@ -60,13 +93,52 @@ const DEFS = [
|
|
|
60
93
|
priority: { type: 'number', description: '优先级(数值越大越先)' },
|
|
61
94
|
dueAt: { type: 'number', description: '截止时间(epoch ms)' },
|
|
62
95
|
sourceSeq: { type: 'string', description: '幂等键:同键重复创建只产生一条' },
|
|
96
|
+
expectedComplexity: {
|
|
97
|
+
type: 'string',
|
|
98
|
+
enum: ['T0', 'T1', 'T2', 'T3'],
|
|
99
|
+
description: '该子任务的复杂度档位(路由用):T0 一句话问答 / T1 常规改动 / T2 跨文件或多步 / T3 架构级',
|
|
100
|
+
},
|
|
101
|
+
requiresPaid: {
|
|
102
|
+
type: 'boolean',
|
|
103
|
+
description: '该子任务是否值得用付费渠道(默认 false ⇒ free_only);只有确实需要强模型时才置 true',
|
|
104
|
+
},
|
|
105
|
+
cycle: { type: 'string', description: '周期名(PDCA 复盘周期标识)' },
|
|
106
|
+
milestone: { type: 'string', description: '里程碑名' },
|
|
107
|
+
estimate: { type: 'number', description: '预估工作量(≥0)' },
|
|
108
|
+
mandateBasis: {
|
|
109
|
+
type: 'string',
|
|
110
|
+
enum: ['explicit', 'inferred', 'task-board', 'room', 'cycle'],
|
|
111
|
+
description:
|
|
112
|
+
'授权依据(借鉴 superagent Mandate):explicit=人明确点名要做 / inferred=按规则推断 / '
|
|
113
|
+
+ 'task-board=任务板派发 / room=房间里的指令 / cycle=周期复盘产物。不传则不记 basis。',
|
|
114
|
+
},
|
|
115
|
+
mandateSender: {
|
|
116
|
+
type: 'string',
|
|
117
|
+
description: '谁下的令(人/会话/Bot 标识)。不传时记录调用者 byId —— 那是事实,不是推断。',
|
|
118
|
+
},
|
|
63
119
|
},
|
|
64
120
|
required: ['subject'],
|
|
65
121
|
additionalProperties: false,
|
|
66
122
|
},
|
|
67
123
|
run: (s, a, exec) => {
|
|
68
124
|
if (!s.board) return failure('board-unavailable', { hint: '任务板未装配(状态目录不可写?)' })
|
|
69
|
-
|
|
125
|
+
try {
|
|
126
|
+
// `mandateBasis`/`mandateSender` 是扁平参数(模型友好),落到 board 时
|
|
127
|
+
// 组装成 `mandate` 对象 —— 校验在 board 侧统一做(未知键会被拒)。
|
|
128
|
+
const { mandateBasis, mandateSender, ...rest } = a ?? {}
|
|
129
|
+
const mandate = {}
|
|
130
|
+
if (mandateBasis !== undefined && mandateBasis !== null) mandate.basis = mandateBasis
|
|
131
|
+
if (mandateSender !== undefined && mandateSender !== null) mandate.sender = mandateSender
|
|
132
|
+
return success({
|
|
133
|
+
task: s.board.create({
|
|
134
|
+
...rest,
|
|
135
|
+
byId: callerOf(exec),
|
|
136
|
+
...(Object.keys(mandate).length > 0 ? { mandate } : {}),
|
|
137
|
+
}),
|
|
138
|
+
})
|
|
139
|
+
} catch (error) {
|
|
140
|
+
return failure(error?.code ?? 'create-failed', { message: error?.message ?? String(error) })
|
|
141
|
+
}
|
|
70
142
|
},
|
|
71
143
|
},
|
|
72
144
|
{
|
|
@@ -103,7 +175,9 @@ const DEFS = [
|
|
|
103
175
|
description:
|
|
104
176
|
'推进任务状态(CAS:必须带当前 expectedRev,不匹配会被拒,绝不静默覆盖)。' +
|
|
105
177
|
'action: claim=取租约并置 in_progress / heartbeat=续租 / release=放租约回 pending / ' +
|
|
106
|
-
'complete=完成(**必须带非空 artifacts**)/ reopen=重开 / block / unblock / delete=tombstone / set=改字段。'
|
|
178
|
+
'complete=完成(**必须带非空 artifacts**)/ reopen=重开 / block / unblock / delete=tombstone / set=改字段。' +
|
|
179
|
+
'结构化收尾:complete 可带 outcome=ready|dropped 与 humanAction(一句话要人做什么);' +
|
|
180
|
+
'block 可带 outcome=blocked|failed 与 humanAction。',
|
|
107
181
|
parameters: {
|
|
108
182
|
type: 'object',
|
|
109
183
|
properties: {
|
|
@@ -115,20 +189,46 @@ const DEFS = [
|
|
|
115
189
|
},
|
|
116
190
|
artifacts: { type: 'array', items: { type: 'string' }, description: 'complete 必填:交付物路径' },
|
|
117
191
|
reason: { type: 'string', description: 'block 的原因' },
|
|
192
|
+
outcome: {
|
|
193
|
+
type: 'string',
|
|
194
|
+
enum: ['ready', 'blocked', 'failed', 'dropped'],
|
|
195
|
+
description:
|
|
196
|
+
'收尾结论(借鉴 superagent Report 枚举):complete 用 ready(默认,等人验收)或 dropped(无需人处理);'
|
|
197
|
+
+ 'block 用 blocked(默认)或 failed(这条路走不通)。传错组合会被拒并指路。',
|
|
198
|
+
},
|
|
199
|
+
humanAction: {
|
|
200
|
+
type: 'string',
|
|
201
|
+
description:
|
|
202
|
+
'一句话说清要人具体做什么(≤1000 字符);block 时建议必填 —— 它显示在「待你决定」列表里。',
|
|
203
|
+
},
|
|
118
204
|
subject: { type: 'string' },
|
|
119
205
|
description: { type: 'string' },
|
|
120
206
|
priority: { type: 'number' },
|
|
121
207
|
dueAt: { type: 'number' },
|
|
122
208
|
writeScopes: { type: 'array', items: { type: 'string' } },
|
|
123
209
|
blockedBy: { type: 'array', items: { type: 'string' } },
|
|
210
|
+
expectedComplexity: {
|
|
211
|
+
type: 'string',
|
|
212
|
+
enum: ['T0', 'T1', 'T2', 'T3'],
|
|
213
|
+
description: '复杂度档位标注(claim 时可补/改;null = 清除)',
|
|
214
|
+
},
|
|
215
|
+
requiresPaid: {
|
|
216
|
+
type: 'boolean',
|
|
217
|
+
description: '是否值得付费渠道(claim 时可补/改;null = 清除;缺省 ⇒ free_only)',
|
|
218
|
+
},
|
|
124
219
|
},
|
|
125
220
|
required: ['id', 'expectedRev', 'action'],
|
|
126
221
|
additionalProperties: false,
|
|
127
222
|
},
|
|
128
223
|
run: (s, a, exec) => {
|
|
129
224
|
if (!s.board) return failure('board-unavailable')
|
|
225
|
+
const byId = callerOf(exec)
|
|
130
226
|
try {
|
|
131
|
-
|
|
227
|
+
const task = s.board.update({ ...a, byId })
|
|
228
|
+
// 契约 §6:子任务被 claim 时,用任务字段给 owner 会话写 hint(付费用「任务标注」说了算)。
|
|
229
|
+
// hint 写失败只是少了优化,**不影响** claim 结果 ⇒ 只作为附加字段回报。
|
|
230
|
+
const hint = a.action === 'claim' ? applyTaskHint(task, byId) : undefined
|
|
231
|
+
return hint ? success({ task, hint }) : success({ task })
|
|
132
232
|
} catch (error) {
|
|
133
233
|
// CAS 冲突等业务失败**返回**给模型(而不是抛崩),模型可重读 rev 后重试
|
|
134
234
|
return failure(error?.code ?? 'update-failed', { message: error?.message ?? String(error) })
|
|
@@ -175,13 +275,23 @@ const DEFS = [
|
|
|
175
275
|
dedupKey: { type: 'string', description: '去重键(强烈建议:如 "task-assigned:<taskId>")' },
|
|
176
276
|
text: { type: 'string', description: '唤醒正文;缺省按 reason 生成' },
|
|
177
277
|
delayMs: { type: 'number', description: '延后投递(ms)' },
|
|
278
|
+
taskId: {
|
|
279
|
+
type: 'string',
|
|
280
|
+
description: '关联任务 id(可选):给了就用该任务的 expectedComplexity/requiresPaid 给目标会话写路由 hint',
|
|
281
|
+
},
|
|
178
282
|
},
|
|
179
283
|
required: ['target', 'reason'],
|
|
180
284
|
additionalProperties: false,
|
|
181
285
|
},
|
|
182
286
|
run: (s, a) => {
|
|
183
287
|
if (!s.dispatcher) return failure('dispatcher-unavailable')
|
|
184
|
-
|
|
288
|
+
const { taskId, ...request } = a ?? {}
|
|
289
|
+
const res = s.dispatcher.notify(request)
|
|
290
|
+
// 契约 §6:唤醒时同样用任务字段写 hint。taskId 显式优先,否则从
|
|
291
|
+
// dedupKey("task-assigned:t-3")反推 —— 平台内部唤醒本来就是这么编键的。
|
|
292
|
+
const hintTaskId = taskId ?? taskIdFromDedup(request.dedupKey)
|
|
293
|
+
const hint = hintTaskId ? hintForTask(s.board, hintTaskId, request.target) : undefined
|
|
294
|
+
return hint ? { ...res, hint } : res
|
|
185
295
|
},
|
|
186
296
|
},
|
|
187
297
|
|
|
@@ -206,6 +316,12 @@ const DEFS = [
|
|
|
206
316
|
'agent 预设 id(决定该 Bot 的人格/系统提示/技能/工具面)。' +
|
|
207
317
|
'不传则用宿主默认预设。可用 bot_roster_list 的 presets 字段或 GET /cs-bots/api/presets 查可选项。',
|
|
208
318
|
},
|
|
319
|
+
prepareCommand: {
|
|
320
|
+
type: 'string',
|
|
321
|
+
description:
|
|
322
|
+
'可选。改造07 · 借鉴 Super-agent:该 Bot 首次接活前在 cwd 下执行的准备命令,' +
|
|
323
|
+
'典型如 `git worktree add ../<name> main`。准备失败会让 claim 拒绝并记录原因。',
|
|
324
|
+
},
|
|
209
325
|
},
|
|
210
326
|
required: ['name', 'cwd'],
|
|
211
327
|
additionalProperties: false,
|
|
@@ -241,14 +357,21 @@ const DEFS = [
|
|
|
241
357
|
name: 'bot_roster_manage',
|
|
242
358
|
description:
|
|
243
359
|
'管理已注册的 Bot(**官方 roster 做不到的能力**):rename=改名(旧名随即释放)/ ' +
|
|
244
|
-
'retire=退役(终态,名字与目录可被复用)/ setCwd=换工作目录 /
|
|
360
|
+
'retire=退役(终态,名字与目录可被复用)/ setCwd=换工作目录 / prepare=设置或清除开工准备命令 / ' +
|
|
361
|
+
'claim=取租约 / release / heartbeat。',
|
|
245
362
|
parameters: {
|
|
246
363
|
type: 'object',
|
|
247
364
|
properties: {
|
|
248
365
|
id: { type: 'string' },
|
|
249
|
-
action: { type: 'string', enum: ['rename', 'retire', 'setCwd', 'claim', 'release', 'heartbeat'] },
|
|
366
|
+
action: { type: 'string', enum: ['rename', 'retire', 'setCwd', 'prepare', 'claim', 'release', 'heartbeat'] },
|
|
250
367
|
name: { type: 'string', description: 'rename 用' },
|
|
251
368
|
cwd: { type: 'string', description: 'setCwd 用(绝对路径)' },
|
|
369
|
+
prepareCommand: {
|
|
370
|
+
type: 'string',
|
|
371
|
+
description:
|
|
372
|
+
'prepare 用(改造07 · 借鉴 Super-agent):Bot 首次接活前在该 cwd 下执行的准备命令,' +
|
|
373
|
+
'典型如 `git worktree add ...`。传空字符串 = 清除。',
|
|
374
|
+
},
|
|
252
375
|
reason: { type: 'string' },
|
|
253
376
|
expectedRev: { type: 'number' },
|
|
254
377
|
},
|
|
@@ -266,6 +389,15 @@ const DEFS = [
|
|
|
266
389
|
return success({ bot: s.roster.retire({ id: a.id, reason: a.reason, byId }) })
|
|
267
390
|
case 'setCwd':
|
|
268
391
|
return success({ bot: s.roster.setCwd({ id: a.id, cwd: a.cwd, expectedRev: a.expectedRev, byId }) })
|
|
392
|
+
case 'prepare':
|
|
393
|
+
return success({
|
|
394
|
+
bot: s.roster.setPrepareCommand({
|
|
395
|
+
id: a.id,
|
|
396
|
+
prepareCommand: a.prepareCommand,
|
|
397
|
+
expectedRev: a.expectedRev,
|
|
398
|
+
byId,
|
|
399
|
+
}),
|
|
400
|
+
})
|
|
269
401
|
case 'claim':
|
|
270
402
|
return success({ bot: s.roster.claim({ id: a.id, owner: byId, expectedRev: a.expectedRev }) })
|
|
271
403
|
case 'release':
|
|
@@ -380,6 +512,8 @@ const DEFS = [
|
|
|
380
512
|
explicit: { type: 'boolean' },
|
|
381
513
|
branch: { type: 'string', description: 'L3 用:限定 git 分支' },
|
|
382
514
|
tags: { type: 'array', items: { type: 'string' } },
|
|
515
|
+
taskId: { type: 'string', description: 'L4 任务笔记用:关联 board 任务 id,notesForTask 据此拉取' },
|
|
516
|
+
phase: { type: 'string', description: 'L4 任务笔记用:plan / doing / block / done' },
|
|
383
517
|
},
|
|
384
518
|
required: ['layer', 'content'],
|
|
385
519
|
additionalProperties: false,
|
|
@@ -414,10 +548,14 @@ const DEFS = [
|
|
|
414
548
|
},
|
|
415
549
|
{
|
|
416
550
|
name: 'bot_memory_context',
|
|
417
|
-
description: '取常驻注入用的记忆文本(L0–L3
|
|
551
|
+
description: '取常驻注入用的记忆文本(L0–L3 冻结快照)。用于拼自己的上下文。可传 tokenBudget 按模型窗口裁剪。',
|
|
418
552
|
parameters: {
|
|
419
553
|
type: 'object',
|
|
420
|
-
properties: {
|
|
554
|
+
properties: {
|
|
555
|
+
branch: { type: 'string' },
|
|
556
|
+
cwd: { type: 'string', description: '按项目裁剪:只注入「全局 + 该项目」的 L3(不传=全局口径)' },
|
|
557
|
+
tokenBudget: { type: 'number', description: '注入 token 预算(0/缺省=不裁剪)' },
|
|
558
|
+
},
|
|
421
559
|
additionalProperties: false,
|
|
422
560
|
},
|
|
423
561
|
run: (s, a) => {
|
|
@@ -425,8 +563,594 @@ const DEFS = [
|
|
|
425
563
|
return success({ text: s.memory.contextFor(a ?? {}) })
|
|
426
564
|
},
|
|
427
565
|
},
|
|
566
|
+
{
|
|
567
|
+
name: 'bot_task_notes',
|
|
568
|
+
description:
|
|
569
|
+
'拉取某个 board 任务的全部 L4 任务笔记(倒序,最新在前)。接手任务时先看任务详情,再调本工具读历史笔记恢复上下文,' +
|
|
570
|
+
'不依赖旧会话消息。笔记由 bot_memory_add(layer=L4, taskId) 写入。',
|
|
571
|
+
parameters: {
|
|
572
|
+
type: 'object',
|
|
573
|
+
properties: {
|
|
574
|
+
taskId: { type: 'string', description: 'board 任务 id' },
|
|
575
|
+
cwd: { type: 'string', description: '按项目裁剪' },
|
|
576
|
+
limit: { type: 'number', description: '最多返回条数(缺省全部)' },
|
|
577
|
+
},
|
|
578
|
+
required: ['taskId'],
|
|
579
|
+
additionalProperties: false,
|
|
580
|
+
},
|
|
581
|
+
run: (s, a) => {
|
|
582
|
+
if (!s.memory) return failure('memory-unavailable')
|
|
583
|
+
try {
|
|
584
|
+
return success({ notes: s.memory.notesForTask(a ?? {}) })
|
|
585
|
+
} catch (error) {
|
|
586
|
+
return failure(error?.code ?? 'task-notes-failed', { message: error?.message ?? String(error) })
|
|
587
|
+
}
|
|
588
|
+
},
|
|
589
|
+
},
|
|
590
|
+
|
|
591
|
+
// ── 待办(TodoService)──────────────────────────────────────────────────────
|
|
592
|
+
{
|
|
593
|
+
name: 'bot_todo_add',
|
|
594
|
+
description: '记一件待办。track: life 生活 / work 工作 / project 本项目 / daily 每日(截止=今天)。'
|
|
595
|
+
+ 'quadrant: q1 重要且紧急 / q2 重要不紧急 / q3 紧急不重要 / q4 都不。',
|
|
596
|
+
parameters: {
|
|
597
|
+
type: 'object',
|
|
598
|
+
properties: {
|
|
599
|
+
track: { type: 'string', enum: ['life', 'work', 'project', 'daily'] },
|
|
600
|
+
content: { type: 'string' },
|
|
601
|
+
quadrant: { type: 'string', enum: ['q1', 'q2', 'q3', 'q4'] },
|
|
602
|
+
due: { type: 'string', description: 'YYYY-MM-DD' },
|
|
603
|
+
cat: { type: 'string' },
|
|
604
|
+
cwd: { type: 'string', description: 'project 轨用:项目工作目录' },
|
|
605
|
+
date: { type: 'string', description: 'daily 轨用:YYYY-MM-DD(缺省=今天)' },
|
|
606
|
+
},
|
|
607
|
+
required: ['content'],
|
|
608
|
+
additionalProperties: false,
|
|
609
|
+
},
|
|
610
|
+
run: (s, a, exec) => {
|
|
611
|
+
if (!s.todo) return failure('todo-unavailable')
|
|
612
|
+
try {
|
|
613
|
+
return success({ todo: s.todo.createTodo({ ...a, by: callerOf(exec) }) })
|
|
614
|
+
} catch (error) {
|
|
615
|
+
return failure(error?.code ?? 'todo-add-failed', { message: error?.message ?? String(error) })
|
|
616
|
+
}
|
|
617
|
+
},
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
name: 'bot_todo_list',
|
|
621
|
+
description: '查待办。缺省只返回需要关注的(逾期/今日到期/当前项目),要全部请传 all=true。'
|
|
622
|
+
+ '查过往每日待办请同时传 past=true 与 expired=true。',
|
|
623
|
+
parameters: {
|
|
624
|
+
type: 'object',
|
|
625
|
+
properties: {
|
|
626
|
+
track: { type: 'string', enum: ['life', 'work', 'project', 'daily'] },
|
|
627
|
+
cwd: { type: 'string' },
|
|
628
|
+
date: { type: 'string' },
|
|
629
|
+
status: { type: 'string', enum: ['pending', 'doing', 'done', 'blocked', 'cancelled'] },
|
|
630
|
+
query: { type: 'string' },
|
|
631
|
+
all: { type: 'boolean' },
|
|
632
|
+
past: { type: 'boolean' },
|
|
633
|
+
expired: { type: 'boolean' },
|
|
634
|
+
limit: { type: 'number' },
|
|
635
|
+
},
|
|
636
|
+
additionalProperties: false,
|
|
637
|
+
},
|
|
638
|
+
run: (s, a) => {
|
|
639
|
+
if (!s.todo) return failure('todo-unavailable')
|
|
640
|
+
return success({ todos: s.todo.listTodos(a ?? {}) })
|
|
641
|
+
},
|
|
642
|
+
},
|
|
643
|
+
{
|
|
644
|
+
name: 'bot_todo_update',
|
|
645
|
+
description: '改待办(必须带 expectedRev 防覆盖)。可改 content/quadrant/due/cat/status。',
|
|
646
|
+
parameters: {
|
|
647
|
+
type: 'object',
|
|
648
|
+
properties: {
|
|
649
|
+
id: { type: 'string' },
|
|
650
|
+
expectedRev: { type: 'number' },
|
|
651
|
+
content: { type: 'string' },
|
|
652
|
+
quadrant: { type: 'string', enum: ['q1', 'q2', 'q3', 'q4'] },
|
|
653
|
+
due: { type: 'string' },
|
|
654
|
+
cat: { type: 'string' },
|
|
655
|
+
status: { type: 'string', enum: ['pending', 'doing', 'done', 'blocked', 'cancelled'] },
|
|
656
|
+
},
|
|
657
|
+
required: ['id', 'expectedRev'],
|
|
658
|
+
additionalProperties: false,
|
|
659
|
+
},
|
|
660
|
+
run: (s, a, exec) => {
|
|
661
|
+
if (!s.todo) return failure('todo-unavailable')
|
|
662
|
+
try {
|
|
663
|
+
return success({ todo: s.todo.updateTodo({ ...a, by: callerOf(exec) }) })
|
|
664
|
+
} catch (error) {
|
|
665
|
+
return failure(error?.code ?? 'todo-update-failed', { message: error?.message ?? String(error) })
|
|
666
|
+
}
|
|
667
|
+
},
|
|
668
|
+
},
|
|
669
|
+
|
|
670
|
+
// ── 便签(ScratchService)──────────────────────────────────────────────────
|
|
671
|
+
{
|
|
672
|
+
name: 'bot_scratch_read',
|
|
673
|
+
description: '读便签(scope 缺省 global)。便签是随手记的地方,不参与任何自动整理。',
|
|
674
|
+
parameters: {
|
|
675
|
+
type: 'object',
|
|
676
|
+
properties: { scope: { type: 'string' } },
|
|
677
|
+
additionalProperties: false,
|
|
678
|
+
},
|
|
679
|
+
run: (s, a) => {
|
|
680
|
+
if (!s.scratch) return failure('scratch-unavailable')
|
|
681
|
+
return success(s.scratch.read(a ?? {}))
|
|
682
|
+
},
|
|
683
|
+
},
|
|
684
|
+
{
|
|
685
|
+
name: 'bot_scratch_write',
|
|
686
|
+
description: '整篇覆盖写便签(不是追加)。要保留原文请先 read 再写回。上限 512 KB。',
|
|
687
|
+
parameters: {
|
|
688
|
+
type: 'object',
|
|
689
|
+
properties: { scope: { type: 'string' }, text: { type: 'string' } },
|
|
690
|
+
required: ['text'],
|
|
691
|
+
additionalProperties: false,
|
|
692
|
+
},
|
|
693
|
+
run: (s, a, exec) => {
|
|
694
|
+
if (!s.scratch) return failure('scratch-unavailable')
|
|
695
|
+
try {
|
|
696
|
+
return success(s.scratch.write({ ...a, by: callerOf(exec) }))
|
|
697
|
+
} catch (error) {
|
|
698
|
+
return failure(error?.code ?? 'scratch-write-failed', { message: error?.message ?? String(error) })
|
|
699
|
+
}
|
|
700
|
+
},
|
|
701
|
+
},
|
|
702
|
+
|
|
703
|
+
// ── 提示词库(PromptService)──────────────────────────────────────────────
|
|
704
|
+
{
|
|
705
|
+
name: 'bot_prompt_list',
|
|
706
|
+
description: '列出提示词模板(可按分类/标签/关键词过滤)。缺省只列启用中的。',
|
|
707
|
+
parameters: {
|
|
708
|
+
type: 'object',
|
|
709
|
+
properties: {
|
|
710
|
+
category: { type: 'string' },
|
|
711
|
+
tag: { type: 'string' },
|
|
712
|
+
query: { type: 'string' },
|
|
713
|
+
enabled: { type: 'boolean' },
|
|
714
|
+
limit: { type: 'number' },
|
|
715
|
+
},
|
|
716
|
+
additionalProperties: false,
|
|
717
|
+
},
|
|
718
|
+
run: (s, a) => {
|
|
719
|
+
if (!s.prompts) return failure('prompts-unavailable')
|
|
720
|
+
return success({ prompts: s.prompts.listPrompts(a ?? {}) })
|
|
721
|
+
},
|
|
722
|
+
},
|
|
723
|
+
{
|
|
724
|
+
name: 'bot_prompt_get',
|
|
725
|
+
description: '取一条提示词的完整正文(含 {{date}}/{{time}} 展开前的原文)。',
|
|
726
|
+
parameters: {
|
|
727
|
+
type: 'object',
|
|
728
|
+
properties: { id: { type: 'string' } },
|
|
729
|
+
required: ['id'],
|
|
730
|
+
additionalProperties: false,
|
|
731
|
+
},
|
|
732
|
+
run: (s, a) => {
|
|
733
|
+
if (!s.prompts) return failure('prompts-unavailable')
|
|
734
|
+
const p = s.prompts.getPrompt({ id: a?.id })
|
|
735
|
+
return p ? success({ prompt: p }) : failure('prompt-not-found')
|
|
736
|
+
},
|
|
737
|
+
},
|
|
738
|
+
|
|
739
|
+
// ── 纪律(DisciplineService,分级)────────────────────────────────────────
|
|
740
|
+
{
|
|
741
|
+
name: 'bot_discipline_list',
|
|
742
|
+
description: '查分级纪律(global 全局 / workspace 工作区 / room 房间 / bot 单个 Bot)。'
|
|
743
|
+
+ '可按 scope/scopeId 过滤。',
|
|
744
|
+
parameters: {
|
|
745
|
+
type: 'object',
|
|
746
|
+
properties: {
|
|
747
|
+
scope: { type: 'string', enum: ['global', 'workspace', 'room', 'bot'] },
|
|
748
|
+
scopeId: { type: 'string' },
|
|
749
|
+
kind: { type: 'string', enum: ['rule', 'requirement', 'principle', 'style'] },
|
|
750
|
+
},
|
|
751
|
+
additionalProperties: false,
|
|
752
|
+
},
|
|
753
|
+
run: (s, a) => {
|
|
754
|
+
if (!s.discipline) return failure('discipline-unavailable')
|
|
755
|
+
return success({ disciplines: s.discipline.listDisciplines(a ?? {}) })
|
|
756
|
+
},
|
|
757
|
+
},
|
|
758
|
+
{
|
|
759
|
+
name: 'bot_discipline_resolve',
|
|
760
|
+
description: '取「我实际要遵守哪些纪律」的合并结果(按层合并、同名去重、优先级排序、预算裁剪)。',
|
|
761
|
+
parameters: {
|
|
762
|
+
type: 'object',
|
|
763
|
+
properties: {
|
|
764
|
+
botId: { type: 'string' },
|
|
765
|
+
cwd: { type: 'string' },
|
|
766
|
+
roomId: { type: 'string' },
|
|
767
|
+
tokenBudget: { type: 'number' },
|
|
768
|
+
},
|
|
769
|
+
additionalProperties: false,
|
|
770
|
+
},
|
|
771
|
+
run: (s, a) => {
|
|
772
|
+
if (!s.discipline) return failure('discipline-unavailable')
|
|
773
|
+
return success(s.discipline.resolveDisciplines(a ?? {}))
|
|
774
|
+
},
|
|
775
|
+
},
|
|
776
|
+
|
|
777
|
+
// ── 建议确认(SuggestService)─────────────────────────────────────────────
|
|
778
|
+
{
|
|
779
|
+
name: 'bot_suggestion_propose',
|
|
780
|
+
description: '提议一条要长期记住的东西(记忆/技能/纪律)。**不会直接生效** —— '
|
|
781
|
+
+ '进入待确认队列,人点了采纳才落库。这是模型改长期记忆的唯一合法途径。',
|
|
782
|
+
parameters: {
|
|
783
|
+
type: 'object',
|
|
784
|
+
properties: {
|
|
785
|
+
kind: { type: 'string', enum: ['memory', 'skill', 'discipline'] },
|
|
786
|
+
layer: { type: 'string', enum: ['L1', 'L2', 'L3', 'L4', 'L5'] },
|
|
787
|
+
payload: { type: 'object', description: 'memory: {content,tags};skill: {name,description,body};discipline: {scope,scopeId,title,content,disciplineKind,priority}' },
|
|
788
|
+
reason: { type: 'string', description: '为什么建议记这条' },
|
|
789
|
+
confidence: { type: 'number' },
|
|
790
|
+
},
|
|
791
|
+
required: ['kind', 'payload'],
|
|
792
|
+
additionalProperties: false,
|
|
793
|
+
},
|
|
794
|
+
run: (s, a, exec) => {
|
|
795
|
+
if (!s.suggest) return failure('suggest-unavailable')
|
|
796
|
+
try {
|
|
797
|
+
// memory 类建议必须带 layer —— 模型漏传时补 L4(任务笔记),而不是让它抛错后丢失
|
|
798
|
+
const payload = { ...a, source: 'model', by: callerOf(exec) }
|
|
799
|
+
if (payload.kind === 'memory' && !payload.layer) payload.layer = 'L4'
|
|
800
|
+
return success({ suggestion: s.suggest.suggest(payload) })
|
|
801
|
+
} catch (error) {
|
|
802
|
+
return failure(error?.code ?? 'suggest-propose-failed', { message: error?.message ?? String(error) })
|
|
803
|
+
}
|
|
804
|
+
},
|
|
805
|
+
},
|
|
806
|
+
{
|
|
807
|
+
name: 'bot_suggestion_list',
|
|
808
|
+
description: '查建议确认队列(缺省 pending)。',
|
|
809
|
+
parameters: {
|
|
810
|
+
type: 'object',
|
|
811
|
+
properties: {
|
|
812
|
+
kind: { type: 'string', enum: ['memory', 'skill', 'discipline'] },
|
|
813
|
+
status: { type: 'string', enum: ['pending', 'accepted', 'rejected'] },
|
|
814
|
+
limit: { type: 'number' },
|
|
815
|
+
},
|
|
816
|
+
additionalProperties: false,
|
|
817
|
+
},
|
|
818
|
+
run: (s, a) => {
|
|
819
|
+
if (!s.suggest) return failure('suggest-unavailable')
|
|
820
|
+
return success({ suggestions: s.suggest.listSuggestions(a ?? {}) })
|
|
821
|
+
},
|
|
822
|
+
},
|
|
823
|
+
|
|
824
|
+
// ── PDCA-4:复盘与标准化(Act)─────────────────────────────────────────────
|
|
825
|
+
{
|
|
826
|
+
name: 'bot_cycle_start',
|
|
827
|
+
description:
|
|
828
|
+
'为一个任务开启 PDCA 复盘周期。阶段:planned→doing→checking→acting→done,不许跳步。\n'
|
|
829
|
+
+ '**kind 决定周期类型(需求4)**:\n'
|
|
830
|
+
+ ' · human(默认)= 人跟长任务,五步不可跳,复盘后人显式确认完成;\n'
|
|
831
|
+
+ ' · agent = 智能体事后归纳,可在 review 时一次性提交并自动闭环(用于定期总结提升)。',
|
|
832
|
+
parameters: {
|
|
833
|
+
type: 'object',
|
|
834
|
+
properties: {
|
|
835
|
+
taskId: { type: 'string', description: '任务 id' },
|
|
836
|
+
objective: { type: 'string', description: '目标原文(防漂移锚)' },
|
|
837
|
+
kind: {
|
|
838
|
+
type: 'string',
|
|
839
|
+
enum: ['human', 'agent'],
|
|
840
|
+
description: '周期类型:human=人跟长任务(默认);agent=智能体归纳(可一次性提交)',
|
|
841
|
+
},
|
|
842
|
+
cycle: { type: 'string' },
|
|
843
|
+
milestone: { type: 'string' },
|
|
844
|
+
estimate: { type: 'number' },
|
|
845
|
+
},
|
|
846
|
+
required: ['taskId', 'objective'],
|
|
847
|
+
additionalProperties: false,
|
|
848
|
+
},
|
|
849
|
+
run: (s, a, exec) => {
|
|
850
|
+
if (!s.cycle) return failure('cycle-unavailable')
|
|
851
|
+
try {
|
|
852
|
+
return success({ cycle: s.cycle.start({ ...a, by: callerOf(exec) }) })
|
|
853
|
+
} catch (error) {
|
|
854
|
+
return failure(error?.code ?? 'cycle-start-failed', { message: error?.message ?? String(error) })
|
|
855
|
+
}
|
|
856
|
+
},
|
|
857
|
+
},
|
|
858
|
+
{
|
|
859
|
+
name: 'bot_cycle_advance',
|
|
860
|
+
description:
|
|
861
|
+
'推进复盘阶段。**human 周期不许跳步**:planned→doing→checking→acting→done,五步都要走。\n'
|
|
862
|
+
+ 'agent 周期(智能体事后归纳)不需要逐步推进:直接 review 即可一次性提交并自动闭环。',
|
|
863
|
+
parameters: {
|
|
864
|
+
type: 'object',
|
|
865
|
+
properties: {
|
|
866
|
+
id: { type: 'string' },
|
|
867
|
+
expectedRev: { type: 'number' },
|
|
868
|
+
phase: { type: 'string', enum: ['doing', 'checking', 'acting', 'done'] },
|
|
869
|
+
progress: { type: 'number' },
|
|
870
|
+
evidence: { type: 'string' },
|
|
871
|
+
},
|
|
872
|
+
required: ['id', 'phase'],
|
|
873
|
+
additionalProperties: false,
|
|
874
|
+
},
|
|
875
|
+
run: (s, a, exec) => {
|
|
876
|
+
if (!s.cycle) return failure('cycle-unavailable')
|
|
877
|
+
try {
|
|
878
|
+
return success({ cycle: s.cycle.advance({ ...a, by: callerOf(exec) }) })
|
|
879
|
+
} catch (error) {
|
|
880
|
+
return failure(error?.code ?? 'cycle-advance-failed', { message: error?.message ?? String(error) })
|
|
881
|
+
}
|
|
882
|
+
},
|
|
883
|
+
},
|
|
884
|
+
{
|
|
885
|
+
name: 'bot_cycle_check',
|
|
886
|
+
description:
|
|
887
|
+
'记录检查结果。pass 前进到 acting,reject 打回 doing 重做。\n'
|
|
888
|
+
+ '这是**人验货**的环节(human 周期用);agent 归纳周期不走检查,别对它调这个。',
|
|
889
|
+
parameters: {
|
|
890
|
+
type: 'object',
|
|
891
|
+
properties: {
|
|
892
|
+
id: { type: 'string' },
|
|
893
|
+
expectedRev: { type: 'number' },
|
|
894
|
+
result: { type: 'string', enum: ['pass', 'reject'] },
|
|
895
|
+
evidence: { type: 'string' },
|
|
896
|
+
},
|
|
897
|
+
required: ['id', 'result'],
|
|
898
|
+
additionalProperties: false,
|
|
899
|
+
},
|
|
900
|
+
run: (s, a, exec) => {
|
|
901
|
+
if (!s.cycle) return failure('cycle-unavailable')
|
|
902
|
+
try {
|
|
903
|
+
return success({ cycle: s.cycle.check({ ...a, by: callerOf(exec) }) })
|
|
904
|
+
} catch (error) {
|
|
905
|
+
return failure(error?.code ?? 'cycle-check-failed', { message: error?.message ?? String(error) })
|
|
906
|
+
}
|
|
907
|
+
},
|
|
908
|
+
},
|
|
909
|
+
{
|
|
910
|
+
name: 'bot_cycle_review',
|
|
911
|
+
description:
|
|
912
|
+
'复盘(Act):记录经验教训,并提议标准化建议(纪律/记忆)。建议走确认制,人采纳才落库。\n'
|
|
913
|
+
+ '**human 周期**:只能在 acting 阶段提交,提交后人显式推进到 done。\n'
|
|
914
|
+
+ '**agent 周期**(智能体定期归纳):任意阶段可直接提交,提交即自动闭环 done(返回 autoClosed=true)。',
|
|
915
|
+
parameters: {
|
|
916
|
+
type: 'object',
|
|
917
|
+
properties: {
|
|
918
|
+
id: { type: 'string' },
|
|
919
|
+
expectedRev: { type: 'number' },
|
|
920
|
+
summary: { type: 'string', description: '复盘总结(≤8000)' },
|
|
921
|
+
lessons: { type: 'array', items: { type: 'string' }, description: '经验教训(≤20 条)' },
|
|
922
|
+
standards: {
|
|
923
|
+
type: 'array',
|
|
924
|
+
items: {
|
|
925
|
+
type: 'object',
|
|
926
|
+
properties: {
|
|
927
|
+
scope: { type: 'string', enum: ['global', 'workspace', 'room', 'bot'] },
|
|
928
|
+
scopeId: { type: 'string' },
|
|
929
|
+
kind: { type: 'string', enum: ['rule', 'requirement', 'principle', 'style'] },
|
|
930
|
+
title: { type: 'string' },
|
|
931
|
+
content: { type: 'string' },
|
|
932
|
+
},
|
|
933
|
+
required: ['scope', 'kind', 'title', 'content'],
|
|
934
|
+
additionalProperties: false,
|
|
935
|
+
},
|
|
936
|
+
},
|
|
937
|
+
},
|
|
938
|
+
required: ['id', 'summary'],
|
|
939
|
+
additionalProperties: false,
|
|
940
|
+
},
|
|
941
|
+
run: (s, a, exec) => {
|
|
942
|
+
if (!s.cycle) return failure('cycle-unavailable')
|
|
943
|
+
try {
|
|
944
|
+
return success(s.cycle.review({ ...a, by: callerOf(exec) }))
|
|
945
|
+
} catch (error) {
|
|
946
|
+
return failure(error?.code ?? 'cycle-review-failed', { message: error?.message ?? String(error) })
|
|
947
|
+
}
|
|
948
|
+
},
|
|
949
|
+
},
|
|
950
|
+
|
|
951
|
+
// ── PDCA-3:测量(metrics)────────────────────────────────────────────────
|
|
952
|
+
{
|
|
953
|
+
name: 'bot_metrics_record',
|
|
954
|
+
description: '记一条 PDCA 测量指标(cycle_start/accept_pass/accept_reject/task_claim 等)。',
|
|
955
|
+
parameters: {
|
|
956
|
+
type: 'object',
|
|
957
|
+
properties: {
|
|
958
|
+
kind: {
|
|
959
|
+
type: 'string',
|
|
960
|
+
enum: ['cycle_start', 'cycle_complete', 'review_proposed', 'review_done',
|
|
961
|
+
'accept_pass', 'accept_reject', 'task_claim', 'task_complete', 'task_blocked',
|
|
962
|
+
'lead_create', 'bot_create', 'room_create', 'turn_end'],
|
|
963
|
+
},
|
|
964
|
+
taskId: { type: 'string' },
|
|
965
|
+
cycleId: { type: 'string' },
|
|
966
|
+
sessionId: { type: 'string' },
|
|
967
|
+
value: { type: 'number' },
|
|
968
|
+
labels: { type: 'object' },
|
|
969
|
+
},
|
|
970
|
+
required: ['kind'],
|
|
971
|
+
additionalProperties: false,
|
|
972
|
+
},
|
|
973
|
+
run: (s, a, exec) => {
|
|
974
|
+
if (!s.metrics) return failure('metrics-unavailable')
|
|
975
|
+
try {
|
|
976
|
+
return success({ record: s.metrics.record({ ...a, by: callerOf(exec) }) })
|
|
977
|
+
} catch (error) {
|
|
978
|
+
return failure(error?.code ?? 'metrics-record-failed', { message: error?.message ?? String(error) })
|
|
979
|
+
}
|
|
980
|
+
},
|
|
981
|
+
},
|
|
982
|
+
{
|
|
983
|
+
name: 'bot_metrics_aggregate',
|
|
984
|
+
description: '聚合测量指标:按 kind 计数 + 求和 + 首末时间。',
|
|
985
|
+
parameters: {
|
|
986
|
+
type: 'object',
|
|
987
|
+
properties: {
|
|
988
|
+
kind: { type: 'string' },
|
|
989
|
+
since: { type: 'number', description: 'epoch ms' },
|
|
990
|
+
},
|
|
991
|
+
additionalProperties: false,
|
|
992
|
+
},
|
|
993
|
+
run: (s, a) => {
|
|
994
|
+
if (!s.metrics) return failure('metrics-unavailable')
|
|
995
|
+
return success({ aggregate: s.metrics.aggregate(a ?? {}) })
|
|
996
|
+
},
|
|
997
|
+
},
|
|
998
|
+
|
|
999
|
+
// ── PDCA-2:验收证据 ──────────────────────────────────────────────────────
|
|
1000
|
+
{
|
|
1001
|
+
name: 'bot_verify_evaluate',
|
|
1002
|
+
description: '对一组产出路径做存在性检查(机器证据,不接受"我完成了")。',
|
|
1003
|
+
parameters: {
|
|
1004
|
+
type: 'object',
|
|
1005
|
+
properties: {
|
|
1006
|
+
artifacts: { type: 'array', items: { type: 'string' }, description: '产出文件路径' },
|
|
1007
|
+
},
|
|
1008
|
+
required: ['artifacts'],
|
|
1009
|
+
additionalProperties: false,
|
|
1010
|
+
},
|
|
1011
|
+
run: (s, a) => {
|
|
1012
|
+
if (!s.verify) return failure('verify-unavailable')
|
|
1013
|
+
return success(s.verify.evaluate(a?.artifacts ?? []))
|
|
1014
|
+
},
|
|
1015
|
+
},
|
|
1016
|
+
|
|
1017
|
+
// ── 大/小团队 ──────────────────────────────────────────────────────────────
|
|
1018
|
+
{
|
|
1019
|
+
name: 'bot_teams_create',
|
|
1020
|
+
description: '创建一个团队。big 团队(人建的)必须带 leadId;small 团队(智能体自建的)leadId 可选。',
|
|
1021
|
+
parameters: {
|
|
1022
|
+
type: 'object',
|
|
1023
|
+
properties: {
|
|
1024
|
+
name: { type: 'string' },
|
|
1025
|
+
type: { type: 'string', enum: ['big', 'small'] },
|
|
1026
|
+
purpose: { type: 'string' },
|
|
1027
|
+
memberIds: { type: 'array', items: { type: 'string' } },
|
|
1028
|
+
leadId: { type: 'string' },
|
|
1029
|
+
},
|
|
1030
|
+
required: ['name', 'type'],
|
|
1031
|
+
additionalProperties: false,
|
|
1032
|
+
},
|
|
1033
|
+
run: (s, a, exec) => {
|
|
1034
|
+
if (!s.teams) return failure('teams-unavailable')
|
|
1035
|
+
try {
|
|
1036
|
+
return success({ team: s.teams.create({ ...a, by: callerOf(exec) }) })
|
|
1037
|
+
} catch (error) {
|
|
1038
|
+
return failure(error?.code ?? 'teams-create-failed', { message: error?.message ?? String(error) })
|
|
1039
|
+
}
|
|
1040
|
+
},
|
|
1041
|
+
},
|
|
1042
|
+
{
|
|
1043
|
+
name: 'bot_teams_list',
|
|
1044
|
+
description: '列出团队(按类型/状态过滤)。大团队是人建的稳定结构,小团队是智能体自建的临时小组。',
|
|
1045
|
+
parameters: {
|
|
1046
|
+
type: 'object',
|
|
1047
|
+
properties: {
|
|
1048
|
+
type: { type: 'string', enum: ['big', 'small'] },
|
|
1049
|
+
status: { type: 'string', enum: ['open', 'closed'] },
|
|
1050
|
+
},
|
|
1051
|
+
additionalProperties: false,
|
|
1052
|
+
},
|
|
1053
|
+
run: (s, a) => {
|
|
1054
|
+
if (!s.teams) return failure('teams-unavailable')
|
|
1055
|
+
return success({ teams: s.teams.list(a ?? {}) })
|
|
1056
|
+
},
|
|
1057
|
+
},
|
|
1058
|
+
{
|
|
1059
|
+
name: 'bot_teams_add',
|
|
1060
|
+
description: '向团队添加成员(需带 expectedRev 做 CAS)。',
|
|
1061
|
+
parameters: {
|
|
1062
|
+
type: 'object',
|
|
1063
|
+
properties: {
|
|
1064
|
+
id: { type: 'string' },
|
|
1065
|
+
expectedRev: { type: 'number' },
|
|
1066
|
+
memberId: { type: 'string' },
|
|
1067
|
+
},
|
|
1068
|
+
required: ['id', 'memberId'],
|
|
1069
|
+
additionalProperties: false,
|
|
1070
|
+
},
|
|
1071
|
+
run: (s, a, exec) => {
|
|
1072
|
+
if (!s.teams) return failure('teams-unavailable')
|
|
1073
|
+
try {
|
|
1074
|
+
return success({ team: s.teams.addMember({ ...a, by: callerOf(exec) }) })
|
|
1075
|
+
} catch (error) {
|
|
1076
|
+
return failure(error?.code ?? 'teams-add-failed', { message: error?.message ?? String(error) })
|
|
1077
|
+
}
|
|
1078
|
+
},
|
|
1079
|
+
},
|
|
1080
|
+
|
|
1081
|
+
// ── 任务订阅(改造07 · 借鉴 Super-agent Subscription 扇出)──────────────────
|
|
1082
|
+
{
|
|
1083
|
+
name: 'bot_task_subscribe',
|
|
1084
|
+
description:
|
|
1085
|
+
'让一个任务订阅某个房间:该房间的**后续消息自动到达这个任务**(作为上下文),'
|
|
1086
|
+
+ '不需要再 @ Bot。只加上下文,**不改变任务状态、不授予开工权力**。幂等:重复订阅返回既有记录。',
|
|
1087
|
+
parameters: {
|
|
1088
|
+
type: 'object',
|
|
1089
|
+
properties: {
|
|
1090
|
+
taskId: { type: 'string', description: '任务 id' },
|
|
1091
|
+
roomId: { type: 'string', description: '房间 id' },
|
|
1092
|
+
note: { type: 'string', description: '可选备注(为什么订阅)' },
|
|
1093
|
+
},
|
|
1094
|
+
required: ['taskId', 'roomId'],
|
|
1095
|
+
additionalProperties: false,
|
|
1096
|
+
},
|
|
1097
|
+
run: (s, a, exec) => {
|
|
1098
|
+
if (!s.subscription) return failure('subscription-unavailable')
|
|
1099
|
+
try {
|
|
1100
|
+
return success({ sub: s.subscription.subscribe({ ...a, by: callerOf(exec) }) })
|
|
1101
|
+
} catch (error) {
|
|
1102
|
+
return failure(error?.code ?? 'subscribe-failed', { message: error?.message ?? String(error) })
|
|
1103
|
+
}
|
|
1104
|
+
},
|
|
1105
|
+
},
|
|
1106
|
+
{
|
|
1107
|
+
name: 'bot_task_unsubscribe',
|
|
1108
|
+
description: '取消任务的房间订阅(终态,不可恢复;需要时重新订阅)。',
|
|
1109
|
+
parameters: {
|
|
1110
|
+
type: 'object',
|
|
1111
|
+
properties: {
|
|
1112
|
+
id: { type: 'string', description: '订阅 id(不是 taskId)' },
|
|
1113
|
+
expectedRev: { type: 'number' },
|
|
1114
|
+
},
|
|
1115
|
+
required: ['id'],
|
|
1116
|
+
additionalProperties: false,
|
|
1117
|
+
},
|
|
1118
|
+
run: (s, a, exec) => {
|
|
1119
|
+
if (!s.subscription) return failure('subscription-unavailable')
|
|
1120
|
+
try {
|
|
1121
|
+
return success({ sub: s.subscription.unsubscribe({ ...a, by: callerOf(exec) }) })
|
|
1122
|
+
} catch (error) {
|
|
1123
|
+
return failure(error?.code ?? 'unsubscribe-failed', { message: error?.message ?? String(error) })
|
|
1124
|
+
}
|
|
1125
|
+
},
|
|
1126
|
+
},
|
|
1127
|
+
{
|
|
1128
|
+
name: 'bot_task_subscriptions',
|
|
1129
|
+
description: '查看订阅:按 taskId / roomId / state 过滤。任务详情用 taskId 拉「订阅了什么」。',
|
|
1130
|
+
parameters: {
|
|
1131
|
+
type: 'object',
|
|
1132
|
+
properties: {
|
|
1133
|
+
taskId: { type: 'string' },
|
|
1134
|
+
roomId: { type: 'string' },
|
|
1135
|
+
state: { type: 'string', enum: ['active', 'dropped'] },
|
|
1136
|
+
},
|
|
1137
|
+
additionalProperties: false,
|
|
1138
|
+
},
|
|
1139
|
+
run: (s, a) => {
|
|
1140
|
+
if (!s.subscription) return failure('subscription-unavailable')
|
|
1141
|
+
try {
|
|
1142
|
+
return success({
|
|
1143
|
+
subs: s.subscription.list(a ?? {}),
|
|
1144
|
+
stats: s.subscription.stats(),
|
|
1145
|
+
})
|
|
1146
|
+
} catch (error) {
|
|
1147
|
+
return failure(error?.code ?? 'subscriptions-failed', { message: error?.message ?? String(error) })
|
|
1148
|
+
}
|
|
1149
|
+
},
|
|
1150
|
+
},
|
|
428
1151
|
]
|
|
429
1152
|
|
|
1153
|
+
|
|
430
1154
|
/**
|
|
431
1155
|
* 注册全部工具。缺 `tools` 服务时**只 warn 不抛**(降级:模型看不到工具,
|
|
432
1156
|
* 但域服务仍可被其他插件/测试直接调用)。
|