Repository navigation
Releases: sddvcm/workbuddy-api
Release list
v0.1.6
v0.1.6
修复重复启动时留下的僵尸进程:进程看起来完全正常,但没有 HTTP 服务,面板打不开。
症状
日志出现端口占用警告后,进程仍在运行、日志继续刷、托盘图标正常出现,但面板打不开:
listen 127.0.0.1:7863 failed: bind: Only one usage of each socket address (protocol/network
address/port) is normally permitted.(面板中将提示)
最容易误判的地方:双击托盘图标打开面板时浏览器访问 127.0.0.1:7863,
请求实际打到了先启动的那个实例。如果那个是升级前的旧版本,用户会以为「面板坏了」,
实际上眼前这个进程的窗口根本不属于它。
根因
cmd/workbuddy-api/main.go 里 StartServer() 的失败分支只 log.Printf 打印警告就继续往下走:
- 调度器照常启动 → 日志继续输出「状态快照为空,跳过本轮记账」;
- 托盘图标照常出现 → systray 与 listener 无关;
- 但
net.Listen从未成功 → 这个进程没有 HTTP 服务,是个只有托盘的空壳。
修复
启动路径绑端口失败即 appInst.Stop() + os.Exit(1),不再留下「看着正常实则没有服务」的进程。
判定为端口占用时额外给出可操作提示(托盘菜单「退出」或 taskkill /IM workbuddy-api.exe /F)
并弹系统通知——否则静默退出,用户看不到任何提示。
面板热切换监听地址的路径不受影响:那条走 SetListen → serveLocked,失败时由 apiError 回 400。
端口占用的判定:两个真实的坑
新加的 isAddrInUse 判定端口占用,实现上踩了两个坑,都已写进代码注释:
一、不能用文本匹配。 strings.Contains(err.Error(), "only one usage") 里的措辞
来自操作系统英文原文,Windows 中文版与其他平台措辞不同,会静默漏判。
二、errors.Is(err, syscall.EADDRINUSE) 在 Windows 上恒为 false(本机实测)。
真实错误链是 *net.OpError → *os.SyscallError → syscall.Errno,最内层 Errno 实测为 10048
(WSAEADDRINUSE);而 syscall.EADDRINUSE 常量值是 536870914(ERROR_ALREADY_EXISTS)——
两个毫无关系的码。errors.Is 对 10048 也匹配不上。
最终实现是逐层 Unwrap 剥到 syscall.Errno 再比数值,Unix(EADDRINUSE=98)与
Windows(WSAEADDRINUSE=10048)两套码都认。
回归测试
新增 cmd/workbuddy-api/startup_listen_test.go:13 个构造用例 + 1 个真实 socket 占端口的守门用例。
守门用例是关键:最初实现用的就是 syscall.EADDRINUSE,13 个构造用例全部通过,
真机一跑立刻失败。这类「判据数值写错」的 bug 构造用例挡不住,必须有真机用例。
关于「已有实例在运行」提示
项目自 v0.1.0 起就有进程级单实例锁(platform.AcquireSingleInstance,
CreateMutex + Local\ 命名空间),且调用位置在 HTTP 服务之前 —— 同版本的两个实例
会在绑端口前就被拦下并提示「程序已在运行」。
如果你仍然看到端口占用警告,说明占着端口的是不走这个锁的进程:多半是早于 v0.1.0
的残留版本,或另一个锁名不同的程序。处置办法:
taskkill /IM workbuddy-api.exe /F
然后重新启动。注意关窗口不等于退进程 —— 托盘是常驻设计(见 R1/R3),
请走托盘菜单的「退出」。
升级方式
- 下载
workbuddy-api-windows-amd64.exe,覆盖旧版即可(配置与账本数据兼容,无需迁移)。 - macOS 用户下载
WorkBuddyAPI-0.1.6-<arch>.dmg。 - Linux 用户下载对应架构的二进制。
本次无新增配置项
config.json 结构不变,老配置直接可用。
v0.1.5
v0.1.5
修复 DeepSeek Harness 桌面版调用 workbuddy 渠道模型时报 400 {"code":11128,"msg":"Illegal API invocation from an unapproved channel"}。
根因:GUI 身份段的 221 字符逐字黑名单
上游内容审核按逐字精确匹配拦截,不做语义判断。此前已定位并处理 DSH 的 system 身份句 You are an AI agent powered by the DeepSeek Harness,但桌面 GUI 版还有第二段身份描述没被覆盖:
You are interacting with the user through the DeepSeek Harness Web GUI whose URL the runtime context names. When the user refers to "this page", "this GUI", or "this app" without naming another target, they mean this GUI.
这段文字的行为极其反直觉,2026-10-21 在 7864 端口架设抓包代理、拿到 DSH 真实请求(12 条消息 / 32 个 tools / 41878 字节)后逐层二分才测清:
| 送入内容 | 结果 |
|---|---|
| 仅首句 S0(107 字符) | 放行 |
| 仅次句 S1(113 字符) | 放行 |
| S0 + 单空格 + S1(221 字符整串) | 拦截 11128 |
| 上述串删任意一个字符 | 放行 |
| 上述串中间插一个空行(222 字符) | 放行 |
| 上述串改任意一个词 | 放行 |
等长无关文本(Z×221) |
放行 |
也就是说黑名单锚定的既不是长度也不是语义,而是这两句话用一个空格连起来的逐字串。此前只按「首句」加特征,命中不到这个跨句组合,所以 DSH 桌面版依旧被拦。
修复走既有的最小改写策略——只换一词,指纹断裂而语义完全不变(this GUI 的指代对象不受影响):
…whose URL the runtime context names.
→ …whose URL the runtime context indicates.
internal/sanitize 与 internal/upstream 两处脱敏表同步补入该特征与改写对(sanitizeRewrites 命中才改写,sanitizeFeatures 负责预检,避免普通请求无谓开销)。
回归测试
新增 internal/upstream/sanitize_dsh_gui_test.go,5 个用例覆盖:改写生效、最小改写(只动一词)、221 字符指纹可被特征表检出、非精确变体不被误改、以及整条出站报文的 wire body 里不再残留任何原指纹片段(最后一条是最关键的守门用例——前四条只验函数,第五条验真实链路)。
go test ./internal/upstream/ -run 'DSH|Sanitize' 共 15 个用例全部通过。
附:DSH 侧配置(非本仓库改动)
若你用 DeepSeek Harness 接入本服务,两处配置需要注意:
~/.dsh/profiles/<profile>/cordis.patch.yml里把@deepseek-ai/dsh-system-prompt的includeHarnessIdentity设为false。官方文档对它的说明是 "Set false only when a compatibility deployment owns the complete system prompt" ——本服务会做脱敏改写,由它接管完整 system prompt 即可。设为false后 DSH 不再注入You are an AI agent powered by the DeepSeek Harness.。- provider 的
baseURL填到/v1为止即可(DSH 自己拼/chat/completions),模型 ID 必须与/v1/models返回值完全一致,含倍率后缀。
升级方式
- 下载
workbuddy-api-windows-amd64.exe,覆盖旧版即可(配置与账本数据兼容,无需迁移)。 - macOS 用户下载
WorkBuddyAPI-0.1.5-<arch>.dmg。 - Linux 用户下载对应架构的二进制。
本次无新增配置项
config.json 结构不变,老配置直接可用。
v0.1.4
v0.1.4
吸收上游两个参考项目(wild-work、workbuddy2api-panel)的更新,修复 5 个问题。
工具结果里的图片不再撑爆上下文与请求体
Codex 这类无状态客户端每轮重放整段历史,工具结果里的截图会以 input_image 块躺在 function_call_output 里。此前转换逻辑取不到文本就回退整块 JSON 序列化,于是整张 PNG 的 base64 变成一条超长文本消息——实测 1.6MB base64 约 146 万 token,1M 上下文的模型直接报 prompt is too long;即便绕过 token,12 张 2048px 截图累积成 33MiB 请求体也会撞上限回 413。
- 工具结果中的图片改走 vision 通道(
image_url内容块),纯文本仍按原样返回字符串; - 图片独占工具结果时补一条
[image]文本占位,避免部分渠道丢弃非 text 块后 content 变空; - 转发前把过大的内联图片(data URL)缩到长边 ≤1568px 并重编码(不透明转 JPEG q85,带透明保持 PNG),按内容哈希缓存 256 条;
http(s)直链不动,解码失败/像素数离谱/体积没变小一律原样返回; - 入站请求体上限 32MiB → 128MiB,并新增配置项
server.max_request_body_mb(可配,钳制在 8~1024MiB,0 = 默认 128)。
整包到期不再被记成「今日消耗」
赠送包整包到期消失时,若该条目此前已被花掉几分,上游回包会呈现 total 下降、used 归零、remaining 下降。旧口径按「余额下降且无到期日」判定为消耗,面板于是显示一笔并不存在的花费。
现在用恒等式 remain = total - used 拆项:total 变小判定为池子缩水(记作到期作废),used 变大才是真消耗。判定设三道门槛——条目无到期日、该渠道被证实分别上报 total 与 used、total 确实下降且上次快照有 total——任一不满足都退回旧口径,对既有渠道零影响。
上游 5xx 默认不再计入账号错误
5xx 的语义是服务端故障,与账号凭据健康无关。旧口径下一次上游 500 风暴会让整池健康账号累计 errCount,达到阈值后全部冷却十分钟,整条渠道 503——而账号的积分、签到、session 一切正常。现在 5xx 默认不计入账号错误,确有需要逐渠道显式开启。
出站请求支持走环境变量代理
显式构造 http.Transport 会覆盖 Go 的默认代理行为,导致自建 Transport 的渠道永远不走代理(HTTP_PROXY / HTTPS_PROXY / NO_PROXY 全部失效)。现已在全部出站 Transport 上显式设置 http.ProxyFromEnvironment。
面板新增「今日作废」列
运行统计的平台表在「今日消耗」旁新增一列,显示因积分包到期/回收而作废的额度(即从今日消耗里扣掉的那部分),便于核对净值消耗的构成。
升级方式
- 下载
workbuddy-api-windows-amd64.exe,覆盖旧版即可(配置与账本数据兼容,无需迁移)。 - macOS 用户下载
WorkBuddyAPI-0.1.4-<arch>.dmg。 - Linux 用户下载对应架构的二进制。
新增配置项
{
"server": {
"max_request_body_mb": 128
}
}省略或填 0 即为默认 128MiB。旧配置文件不含该字段时行为即为 128MiB。
v0.1.3
v0.1.3 — 修复 DeepSeek Harness 请求被 11-128 拦截
⚠️ 本版核心修复:DeepSeek Harness(DSH) 请求 400 code=11-128
现象
用 DeepSeek Harness 走 workbuddy 渠道时报错:
本轮运行失败400 {"code":"11-128","msg":"Illegal API invocation from an unapproved channel"}
请求被拦截,请重新发送
根因
上游对 system 消息开头的逐字串
You are an AI agent powered by DeepSeek Harness 做锚定匹配,命中即整单拦截。
DSH 每个 Agent 请求的 system 消息必带这句,所以 100% 命中 —— 不是账号问题、
不是额度问题、不是客户端问题。
为什么换 traework 就正常? traework 走的是 Trae 上游,没有这套渠道校验。
所以「同一客户端、换个渠道就好了」正是这个根因的典型表现。
修复方式
出站请求体脱敏时,对该身份句做最小语义扰动改写:插入冠词 the
You are an AI agent powered by DeepSeek Harness
→ You are an AI agent powered by the DeepSeek Harness
逐字指纹被破坏、语义不变,上游放行(实测 200)。
缺 You are an 前缀的非精确变体上游本就不拦,保持原样不动,避免误伤。
影响范围:仅 workbuddy / workbuddyai 两条 WorkBuddy 系链路的出站 body。
账号、额度、模型、请求头、调度逻辑均未改动。
其他改动
- 版本号 0.1.2 → 0.1.3(面板显示与 exe 文件属性同步对齐)
.gitignore忽略.workbuddy/(本地工作记忆不入公开仓库)
升级方式
直接替换 exe 即可,无需迁移任何配置或账号数据。
快速开始
- 下载对应平台的产物,放到任意目录
- 双击启动 —— 首次启动会自动生成随机 API Key 并打印在日志里
- 浏览器打开面板,添加账号
接入 AI 客户端
Base URL: http://127.0.0.1:7863/v1
API Key: 见面板顶栏(点击可复制)或 config.json 的 api_key
模型 ID 需带渠道前缀:workbuddy/glm-5.3-flash、traework/<model> 等。
主要特性
- 多渠道账号池 —— 统一调度、冷却、限流避让,按策略挑号(临期优先 / 积分优先 / 负载均衡)
- 会话粘性 —— 同一段对话恒定走同一账号,上游 prompt 缓存可命中
- WAF IP 级 fail-fast —— 多个账号接连撞 WAF 403 时判定为出口 IP 被拦,立即失败而非继续轮转
- 费率与模型清单 —— 多渠道的模型与倍率,支持搜索与比价
- 积分明细 —— 按账号查看可用 / 不可用积分小计
- 自动签到 —— 每日定时签到与保活
- OpenAI / Anthropic 双协议兼容
安全说明
首次启动会随机生成 API Key(不使用固定默认值 —— 固定值会随二进制公开)。
若监听 0.0.0.0 而 api_key 为空,程序会拒绝启动。
面板监听非环回地址时必须配置 admin_password。
系统要求
- Windows 10+ / macOS / Linux(各平台产物见本 Release 附件)
- 无需管理员权限
免责声明
本项目只是各上游渠道的集成与聚合,本身不涉及任何逆向分析和破解工作。
各渠道接口参数、签名算法等底层知识来自社区其他开源项目的公开成果。
仅供个人学习使用,请勿用于商业用途或违反上游服务条款的场景。
workbuddy-api v0.1.2 — 账号轮换可配置 + 安全响应头与访问日志
功能与改进
账号池调度
max_rotate 现在可以配置了。 原先单请求最多轮换几个账号写死在代码里(3),
config.json 与面板都改不了。账号多、且大量账号处于冷却时,3 次可能过早放弃 ——
把「本可成功」的请求判成 503。现支持 config.max_rotate 与环境变量
WILDWORK_MAX_ROTATE,范围 1~20(每个候选至少一次完整上游往返,配得过大只是把
单请求放大成 N 次网络调用)。默认值仍是 3,行为不变。
安全
新增安全响应头。 面板与接口现在都会带上:
| 响应头 | 作用 |
|---|---|
X-Frame-Options: DENY |
防点击劫持(面板会渲染上游返回的文本,这条最实际) |
X-Content-Type-Options: nosniff |
阻止 MIME 嗅探 |
Referrer-Policy: no-referrer |
不把带凭据的 origin 泄出 |
Cross-Origin-Opener-Policy: same-origin |
隔离浏览上下文 |
Cross-Origin-Resource-Policy: same-origin |
关闭不必要的跨源读取 |
Content-Security-Policy |
仅 HTML 文档,附带防注入的三条基础约束 |
关于 CSP 的强度:目前前端存在内联样式与内联事件属性,且图表库走外部 CDN,
因此 CSP 必须放开unsafe-inline,它不是完整的 XSS 防护。
实际生效的是防点击劫持与object-src/base-uri/form-action约束。
想完全收紧需要先改造前端,那是独立的一次改动。
新增访问日志。 落盘到 data/app.log,格式为
access 方法 路径 状态码 字节数 耗时。只记录元数据,不记录请求体与响应体
(里面是你的提示词与模型输出)。此前想复盘「昨天那次为什么失败」是做不到的 ——
请求日志是 128 条内存环形,重启即丢。
非环回监听时更严格。 维持原有行为:对外监听 + 空管理密码 = 拒绝启动。
版本号显示已修正
本版本面板 logo 旁显示的是正确的 v0.1.2,文件属性里的「文件版本」也是
0.1.2.0。上一版 v0.1.2 的 exe 曾显示 v0.1.0、文件属性 1.0.0.0 ——
两个版本号来自不同来源且从未同步。现已改为单一来源(代码里的 const Version),
RT_VERSION 资源由构建脚本自动读取,不再手写。
升级说明
直接替换 exe 即可。config.json 会自动补上新增的 max_rotate 字段(默认 3)。
如果你是从 v0.1.1 升级:v0.1.1 已经移除了「首次启动自动导入其他目录账号」
的功能,本版本延续该行为 —— 账号只能通过面板登录,或手工把 auths/*.json
拷入程序目录。程序不会扫描你的用户目录。
快速开始
- 下载
workbuddy-api-windows-amd64.exe,放到任意目录 - 双击启动 —— 首次启动会自动生成一个随机 API Key 并打印在日志里
- 浏览器打开面板,添加账号
客户端配置:
Base URL : http://127.0.0.1:7863/v1
API Key : 启动日志里那一串(或在面板「设置」里查看)
模型名 : GET /v1/models 可查,或直接用 qodercn/glm-5.2 这类带前缀的
校验
Windows 用户如遇 SmartScreen「未知发布者」提示,这是未做代码签名的正常现象。
二进制以 -trimpath -s -w 构建,已自检不含编译机的绝对路径与凭据。
校验值
SHA-256 a42e0abf1ee114837fcb23c1359d8cf73cb0176fd760f638962e0e558d9ed55f
v0.1.1
⚠️ v0.1.1 安全修复
v0.1.1 移除了「首次启动自动从其他目录导入账号凭据」的功能。
旧版在真首次启动时会探测两个目录(开发者的旧项目路径,以及
%USERPROFILE%\wbsync�uild�in),若其中存在 auths/*.json 就把里面的
登录态凭据(access/refresh token)复制进新目录。该行为存在三个问题:
- 公开源码里暴露了开发者的私人部署路径;
- 扫描用户主目录属于未经请求的数据获取;
- 静默复制凭据是明确的隐私问题,用户完全无从预期。
若你从 v0.1.0 升级且不需要该行为,直接替换 exe 即可。
需要迁移账号时,请在面板里重新登录,或手工把 auths/*.json 拷入程序目录。
快速开始
- 下载
workbuddy-api-windows-amd64.exe,放到任意目录 - 双击启动 —— 首次启动会自动生成一个随机 API Key 并打印在日志里
- 浏览器打开面板,添加账号
接入 AI 客户端
Base URL: http://127.0.0.1:7863/v1
API Key: 见面板顶栏(点击可复制)或 config.json 的 api_key
模型 ID 需带渠道前缀:workbuddy/glm-5.3-flash、traework/<model> 等。
主要特性
- 多渠道账号池 —— 统一调度、冷却、限流避让,按策略挑号(临期优先 / 积分优先 / 负载均衡)
- 会话粘性 —— 同一段对话恒定走同一账号,上游 prompt 缓存可命中,避免工具调用 ID 对不上
- WAF IP 级 fail-fast —— 多个账号接连撞 WAF 403 时判定为出口 IP 被拦,立即失败而非继续轮转
- 费率与模型清单 —— 11 个渠道的模型与倍率,支持搜索与比价
- 积分明细 —— 按账号查看可用 / 不可用积分小计
- 自动签到 —— 每日定时签到与保活
- OpenAI / Anthropic 双协议兼容
安全说明
首次启动会随机生成 API Key(不使用固定默认值 —— 固定值会随二进制公开,
任何人下载 exe 就能反查到默认 key)。若监听 0.0.0.0 而 api_key 为空,
程序会拒绝启动,避免上游额度被局域网任意设备消耗。
面板监听非环回地址时必须配置 admin_password。
系统要求
- Windows 10+(本 Release 的手传资产仅 Windows amd64)
- 无需管理员权限
macOS / Linux 版本由 GitHub Actions 构建,见该 Release 的其他附件。
免责声明
本项目只是各上游渠道的集成与聚合,本身不涉及任何逆向分析和破解工作。
各渠道接口参数、签名算法等底层知识来自社区其他开源项目的公开成果。
仅供个人学习使用,请勿用于商业用途或违反上游服务条款的场景。