dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
一人公司 · DeepSeek Harness 多 agent 公司编排插件(CEO/项目群/大厅/@派活/审批/排班/工作日志)
给 DeepSeek Harness(dsh)加一层「公司」:你当董事会,agent 当员工。
每个员工是一等的 dsh 会话 agent,有岗位说明书、模型路由、工位目录和一套公司协作工具;
公司服务(ctx.company)负责名册、任务、信箱、审批、定时排程、资料库权限与工作日志。
完全自包含:只依赖 dsh 官方核心服务(agents/tools/commands/systemPrompt/storageDomain/sessionPersistence/timer),不依赖任何第三方插件。
# 从 GitHub 安装(仓库自带 lib/ 构建产物,无需允许构建脚本)
dsh plugin --profile web add "github:xiazhi88/dsh-onecompany"
# 或本地开发用 link 安装
dsh plugin --profile web add /path/to/dsh-onecompany
dsh --profile web # 重启后生效
重启后:
/company 命令:status、org、tasks、assign <员工> <任务>、inbox、approve|reject <id>、on|off。页面右上「停用 / 启用」(等价于 /company off|on):
company_disabled;也就是说:不想用公司模式时,dsh 与你平时完全一样。
在「组织」页招聘:姓名、职位、汇报对象、岗位说明书(persona → 同时落 <工位>/AGENTS.md)、模型、每日 token 预算。
resume;maxResidentAgents LRU 回收,会话日志始终保留,可随时冷恢复;agent-default-model);不要留空到没有任何模型,否则提示词里的 {{model}} 无法求值、请求会失败(插件已在创建时自动继承默认路由);| 工具 | 用途 |
|---|---|
company_org | 组织架构与通讯录 |
company_mail_send / company_mail_list | 公司信箱收发(info / question / request / report) |
company_task_create / _list / _update / _comment | 任务:建、查、认领与推进、评论区讨论 |
company_report | 向上级(无上级则达董事会)汇报 |
company_approval_request | 越权动作(花钱 / 上线 / 高危 / 招聘)申请审批 |
company_doc_list / _read / _write | 资料库读写(按项目 ACL 判定) |
company_schedule_create / _list / _delete | 自己的定时任务(cron / every / at) |
company_help | 协作协议速查 |
工具描述里写明了「什么时候用哪个」,配合岗位提示词里的协议段,员工会自己走完 收信 → 认领 → 执行 → 评论 → 提交验收 → 汇报 的闭环。
session/event 折叠轮次与工时,llm/stream 旁路捕获 token 四桶(输入/输出/缓存读/缓存写 + 推理),按员工与日期聚合;面板「组织 → 工作日志」可看明细。在面板里新建一条排程,到点 host 会把 prompt 作为一条消息投给指定员工(等于替董事会说那句话):
| 形态 | 填法 | wire |
|---|---|---|
| N 小时后做一次 | 小时数(可小数,0.5 = 30 分钟) | kind: 'at' + ISO 时间戳 |
| 每 N 小时做 | 小时数 | kind: 'every' + 秒数(≥ 60) |
| cron 表达式 | 五段 cron,按公司时区解释 | kind: 'cron' |
company_schedule_create / list / delete(例如「每 6 小时自检一次」)。cordis.patch.yml)- insert:
- id: onecompany
name: dsh-onecompany
config:
companyRoot: '' # 公司根目录;空 = $DSH_HOME/onecompany
companyName: 一人公司
tickMs: 30000 # 调度/投递周期
maxResidentAgents: 8 # 常驻员工上限
defaultDailyTokenCap: 5000000
approvalsRequired: [hire, spend, strategy, danger]
timeZone: Asia/Shanghai
目录布局:<root>/employees/<员工id>/(工位,含 AGENTS.md)、<root>/library/(公司资料库)、<root>/projects/<项目id>/(项目文件)。
storage domain onecompany v1(json 后端):agents / projects / docs / tasks / comments / messages / approvals / schedules / worklogs / activity + 全局槽位(开关与公司名)。业务数据不写进会话事件 schema,避免污染会话日志。
company_disabled 的教学文本。onecompany-role 段(order 60)注入岗位、通讯录、当前任务与工作纪律;岗位说明书另落 AGENTS.md。【公司信箱】 / 【新任务】 / 【定时任务】 / 【审批请求】 / 【审批结果】),动态值 JSON 转义。--dsw-alias-brand-primary 在深色主题下是「近白色」,拿它做按钮底色再配白字就是白底白字。面板自带 --oc-accent 蓝色系,前景/背景成对定义。color-mix(状态色, --oc-fg),深色偏亮、浅色偏深,两套主题都可读。.oc-shell 为定位父级,.oc-modal__body 滚动、footer 常驻,长表单不会把按钮滚出视野。minmax(0,1fr)),窗口窄时才横向滚动;卡片信息分「标题 + 优先级角标」「负责人 + 紧凑时间(12m/3h/09-18)」两行。新的会话地图
| 会话 | 谁在驱动 | 作用 |
|---|---|---|
| 「一人公司 · 大厅」 | CEO 司南 | 董事会指令入口 + 全公司简报/周报 |
| 「项目名 · 项目群」 | CEO 的项目实例 | 该项目一切汇报与派活(汇报默认落这里) |
| 「员工名 · 工位」 | 员工本人 | 任务帧落点 + 执行现场(偏审计) |
company_report 按任务的项目归属归口。投递模式由 reportDelivery 决定:
digest(默认):投到项目群/大厅,由 CEO 转成给董事会的易读简报(一轮模型调用);record:不叫醒任何 agent——原文追加进项目档案的《汇报流水》,同时进面板未读信箱(零 token、零回声)。
审批/阻塞类仍会正常送达需要裁决的人。@员工名(@ 是共享多分组触发器,与原生文件引用、子会话并列,name: onecompany 唯一)→ 模型调 company_call;② /call <员工> <任务>(命令直达,不经模型);③ /company assign。ctx.sessionTitle.rename)。SessionSummary.blank)。可用 kickoffOnCreate: false 关闭。parentSession 血缘把子会话 token/工时归集到员工。standard),员工因此有 bash/fs/子 agent/压缩(v1 漏挂导致「员工无 shell」的教训)。新增配置项:
autoProvision: true # 启动时自动补建 CEO 与项目群会话
kickoffOnCreate: true # 新建会话后发开场消息(让会话出现在侧栏)
reportDelivery: record # digest = CEO 转简报;record = 只归档 + 面板未读(不叫醒 agent)
公司名册、项目与岗位说明书都是你的数据,不属于插件本体。两种起步方式:
A. 面板搭建(推荐):重启后打开「公司面板 → 组织 → 招聘」,填姓名/职位/负责项目/岗位说明书/模型,员工首次收到消息时自动创建会话。
B. 脚本初始化(一次成型):复制 scripts/seed-example.mjs,把顶部的仓库路径换成你自己的,然后
node scripts/seed-example.mjs --dry-run # 先看计划
node scripts/seed-example.mjs # 写入
# 重启 dsh web:公司服务会补齐 CEO、大厅与项目群会话,并投递接手任务
岗位说明书写法参考 examples/agents/example-role-brief.md(含「负责/不负责、运行与验证、纪律、协作协议」四段)。
src/host/ host 半:domain 模型、CompanyService、员工/频道驱动、公司工具、命令、根会话注入、Typert Remote
src/client/ 浏览器半:公司整页(组织/任务/审批/资料库/动态)、入口按钮与红点、@ 员工提及源、Remote 适配
src/shared/ 两侧共用的 zod 线路类型(domain 表、Remote codec、UI 快照)
agents/ 包内岗位说明书(`agt_ceo.md` 是 CEO 默认说明书,启动时用于补建 CEO)
scripts/ 初始化示例与运维脚本
lib/ 构建产物(随仓库提供,从 GitHub 安装即可用,无需构建授权)
taskSession)默认 per-task:每个任务一个一次性执行会话,跑完即停(会话保留、可随时重开)。
员工 = 身份(名册:姓名/职位/模型/预算/权限)
├─ 执行:任务会话 task.sessionId cwd=项目仓库 标题 `tsk_xxx · 任务简述`
│ 以 origin:'subagent' 挂在**派发它的会话**下 → 不进侧栏,
│ 只显示在父会话标题栏的「N 个子代理」里(面板任务详情可一键打开)
├─ 对话:工位会话 agent.sessionId 仅用于董事会直接找他说话(懒创建)
└─ 记忆:项目档案 + 交接清单 + 任务评论(真源,不进上下文)
父会话是谁:你用 @员工 或在某个会话里派活 → 父会话就是你正在看的那个会话;
司南在项目群里派 → 父会话是该项目群;从面板派 → 父会话是公司大厅。
历史任务在启动时归位:带项目且有项目群的一律归该项目群(含早期被错写成大厅的任务);
无项目的归大厅。所以升级后老任务的汇报也会回到正确的项目群。
派发人:任务记录 dispatcherName(董事会 / 司南 / 某员工)+ parentSessionId(哪个会话)。
任务详情显示派发人与「打开派发会话」;任务会话的提示词里也写明「由谁派发、汇报会回到那里」。
汇报回投:company_report 除了归档(《汇报流水》)和进董事会信箱,还会把原文
以通知行形式回投到派发它的那个会话(项目群 / 大厅 / 你自己的会话)——派活的人在那里就能看到结果。
在会话顶部的归纳:任务会话在侧栏是隐藏的,但派发它的那个会话标题栏会出现 「N 个任务 ▾」(本插件自带的入口,紧挨「司 公司」),展开即列出本会话派出的任务 (状态图标 + 任务 id / 负责人 / 中文状态),点一下直接打开它的执行会话。 状态图标带动效:进行中转圈、阻塞与待验收呼吸、完成打勾、待办空心、取消灰线。
在任务会话里能回去:任务会话的标题栏会有「← 返回主会话」(父会话是大厅/项目群时 显示具体名字,否则显示「主会话」),点一下回到派发它的那个会话。
为什么不用平台原生的「N 个子代理」下拉:那个列表要求子会话由子代理运行时创建 (带 subagent 生命周期投影),而我们的员工需要自己的工具面与岗位提示词,只能由插件 组合创建;标上
origin: 'subagent'后它会一直卡在「正在加载子代理…」。所以改成 「保留血统 + 不标 subagent + 自己做归纳入口」。
review / done / cancelled → 登记待停,由 tick 在 agent 空闲后停止会话
(常驻位释放,会话可重开)。⚠️ 不能当场停:handle.dispose() 会等当前轮次结束,
而从这轮自己的工具调用里 await 它必然死锁(工具等轮次、轮次等工具);taskSessionTimeoutHours(默认 12)内没收尾 → 停止会话 + 在任务里留一条说明(僵尸会话不占位);company_doc_read 按需读全文,
交活必须写档案(company_doc_write)——这样下一个任务的会话不需要旧会话的历史;改成 resident 即回到常驻工位模式(有连续性,但上下文随会话年龄增长、且会互相污染)。
公司模式比单人会话贵得多,原因是每一步都要把固定前缀重发一遍。本机实测(2026-09-20):
| 项 | 数值 |
|---|---|
| 公司当天输入 | 166M tokens(步骤级累计;其中 86% 命中前缀缓存) |
| 其中司南(大厅 + 2 个项目群三个实例) | 84.6M(约一半) |
| 单次请求工具 schema | 优化前 66k 字符(76 个工具)→ 优化后 32k(54 个) |
已实施的优化
leanTools):把「会话迁移 / 编排 / 可视化」等与公司工作无关的宿主级工具
从模型视野移除(ctx.tools.restrict),工具 schema −47%,每步固定开销减半。compactPrompt):动态清单(当前任务、未完成任务、档案列表)
不再内联进系统提示词——它们每轮都在变,会让整段对话历史的缓存失效、按全价重算;
改为用时 company_task_list / company_doc_list 查。defaultDailyTokenCap(员工默认 2M)与 ceoDailyTokenCap(默认 8M),
超限即暂停该 agent 的信箱投递到次日,并在面板/大厅提示。
⚠️ 兜底只补「从没设过」的 agent:董事会在面板里设过(包括显式设成「不限」)就记
budgetPinned,重启不会再被打回默认值。reportDelivery: record(汇报不叫醒)、employeeKickoff: false(入职不发开场)。还可以再省的(按收益排序)
effort 字段可降推理强度(思考 token 也计费)。唯一注册点是 agent/created 上的 installCompanyAgentInjector(src/host/injector.ts):
它按 service.companyRoleOf(sessionId) 判断这个 agent 是公司角色(大厅 / 项目群 / 员工工位 /
任务会话)后,注册对应的公司工具与岗位提示词。
为什么必须放这里(而不是驱动器的 setup):
setup 只有插件自己创建/恢复会话时才会被调用;setup
——那样那个会话会被组合成普通 agent,company_* 全部 unknown tool(这个坑踩过两次);agent/created 在首次提示词装配之前发生,因此在这里注册是安全且完整的。推论:驱动器的 composeWith 只负责「挂哪个 preset + 收窄工具面」,不允许再注册工具与
提示词(重复注册会抛 duplicate)。
实测事故:董事会只安排了几个任务,公司一天烧到 ¥19.51(平常 ¥3–5)、 7324 次调用、非缓存输入 77.9M——原因是链式续派:任务完成 → 汇报回投唤醒 CEO → 它认为"还有下一批" → 再派一条 → 循环(顾砚一人被派了 18 条「下一刀 / 下一批 / 下批 / 队列批」)。
| 闸门 | 规则 | 效果 |
|---|---|---|
| 派活来源 | agent 只能在董事会触发的轮次里派活。汇报回投 / 排程 / 转投触发的轮次调用 company_dispatch → 拒绝 not_board_triggered | 掐断链式续派 |
| 自我排程 | agent(含 CEO)不得 company_schedule_create;排程只能董事会在面板建 | 掐断自我唤醒链 |
| 任务级预算 | taskTokenCap(默认 8M,输入+输出+缓存合计):单个任务会话超限即停 + 任务留言 | 单任务不再能跑到几亿 |
外加:员工本来就没有派活/建任务权(工具面里不出现 + 服务端拒绝),已在实测中确认有效。
deliverToSession 之类为了往任意会话投递而
resume 一个会话时,如果目标是公司会话(大厅/项目群/工位/任务会话),必须走各自的组合
通道(ensure / ensureChannel / ensureTask)。否则那个会话会被重新组合成一个只有
平台工具的普通 agent —— 表现是所有 company_* 工具报 unknown tool。现在服务按
归属选通道,driver 里还有 isCompanySession 兜底直接拒绝。dispose():handle.dispose() 会等当前轮次结算,
从这轮的工具调用里同步 await 必然死锁。收尾停会话要「登记 + 空闲后由 tick 停」。compactPrompt 就是为此)。lib/client.js 535KB(minify 后,gzip 113KB)。其中约 400KB 是 zod:客户端的 generated Remote 装配要求 strict codec(zod 实例),因此 src/client/remote.ts 必须带 host 清单的 schema。试过用构建期生成的纯数据描述符(src-json)把包压到 137KB,但装配层直接拒绝(generated Remote <field> has no strict codec),因此保留现状。rename 一次(幂等),日志里会有多条 session/title;可优化为「仅在创建时写」。company_report → 项目群 的链路已实现,但需要在真实汇报发生时才会跑通(本机重启后由员工自然触发)。npm install
npm run build # esbuild:lib/index.js(host)、lib/typert.js(Remote 清单)、lib/client.js(浏览器半)
npm run typecheck
node build.mjs --watch
host 半经 dsh plugin add 装进 profile;浏览器半由宿主扫描 dsh.client 标记经 /plugins/ 下发(pnpm run dev:web 时热更新)。