Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
dc6622c
fix(upstream): always send the conversation channel header trio
watsonctl Oct 16, 2026
679e240
fix(server): request illegal 不再永久禁用账号,改为软冷却
luohaonan365 Oct 16, 2026
8b7d43b
fix(upstream): 同账号 refresh 单飞,避免 RT 复用撞 12153 掉登录 (#215)
louddong Oct 18, 2026
cee697a
fix(pool): 软冷却到期后不再透出过期 reason,修面板「可用+历史429」并排(issue #171 问题一)
ftf112233 Oct 17, 2026
c8e920d
fix(server): 缓存告警假阳性——miss 显式存在时对称反推 hit(issue #170)
ftf112233 Oct 16, 2026
76c3bdb
fix(panel): 到期提醒快照与「检查」同口径,按日聚合到期批次
SunshineR04 Oct 17, 2026
618845d
Add files via upload
Auddoss Oct 12, 2026
69071f2
fix(upstream): classify 6021 queue.full as channel-level busy, stop p…
YahooYuan666 Oct 15, 2026
7759e81
fix(server): /v1/models 拉取 CN 模型目录失败时记录 WARN
zhiqiangme Oct 18, 2026
5a69e1f
feat(panel): 展示 Global 模型可用性
vu1Art1st Oct 18, 2026
f3af426
panel: 「一键完成全部」入口一并门控企业切换会话(补缺口)
jiangwanying Oct 16, 2026
884909f
feat(models): add models.hidden blacklist (list filtering + chat gating)
mapxn Oct 19, 2026
05f6be9
feat(pool): 裸模型名跨域回退开关(issue #135)
zkmydgth Oct 19, 2026
478c49b
feat(config): 新增 cn.chat_base 覆盖国内版上游 base
zhiqiangme Oct 18, 2026
8e79304
fix(upstream): 识别 11158 模型权限错误
vu1Art1st Oct 18, 2026
667fa0b
auth: 识别企业切换会话(token_source=enterprise_switch),行为类成长任务门控跳过并提示重登
jiangwanying Oct 12, 2026
48f2eba
fix(panel): 一键完成遇「已达标未领」先补领再跳过(issue #174 顺带项)
ftf112233 Oct 17, 2026
d89c325
feat(panel): 任务补领清扫——周期幂等补领「已达标未领」的成长任务奖励(issue #174 主体链路)
ftf112233 Oct 17, 2026
8549291
feat: add support for proxy from environment variables
folltoshe Oct 18, 2026
48a9c38
feat(compensation): 补偿状态可观测化——先查后领 + 截止倒计时 + 面板入口(issue #189)
Oct 16, 2026
b717336
feat(panel): 支持静态 API Key 账号(无成长体系 / 企业口径额度)
BelovedYaoo Oct 16, 2026
d0dad9e
fix(auth): 拆分成长门控为「硬不成长」与「行为事件不计分」两层
Oct 20, 2026
8499030
feat(panel): 账号备注(账号池与用量同步)与积分到期提醒折叠
Apageoflove Oct 15, 2026
9c0760c
fix(panel): 模型级 6004 双时钟——until<resetAt 时主文字明示两时刻、倒计时跟随 until(issue #…
ftf112233 Oct 17, 2026
efd53f8
feat(pool): 支持按地区独立配置轮询和顺序耗尽调度
SDCOM-0415 Oct 12, 2026
579f98c
fix(config): 面板保存配置不再因 tmp 目录不可写而失败(issue #226 / #134)
Oct 20, 2026
d74521c
fix(server): 区分「渠道校验拦截」与「账号封禁」两种 request illegal(issue #197)
Oct 20, 2026
2e72dc8
fix(upstream): 11140 账号封禁不得因夹带渠道校验文案而降级为软冷却
Oct 20, 2026
0bf6250
fix(upstream): 按业务码分流 11-128/11128 通道校验失败与 11140 账号限制
Oct 20, 2026
49cf38d
fix(pool): 覆盖性修复——成长任务门控/快过期梯度/积分台账/不限量权重/积分燃尽熔断/单号旅行/tool_call 去重(is…
Oct 20, 2026
e2f576b
fix(global): 补齐官方客户端出站指纹,修 issue #231 国际版全池「渠道校验」禁号
misakano7545 Oct 20, 2026
610bc1e
feat(global): 目录探测缓存可失效 + 记录目录来源(issue #216 现象3)
Oct 20, 2026
762ff7b
fix(upstream): 按双版本真机抓包修正出站指纹(7 处)
misakano7545 Oct 20, 2026
9260cb7
feat(panel): 「重新获取」真重探 global 目录 + 目录来源可见(issue #216 现象1/3)
Oct 20, 2026
509e7a6
fix(upstream): 11140 信封里的模型级限流文案不得被当成账号封禁
Oct 20, 2026
ac61d87
fix(server): 11-128 通道校验必须继续轮转,且不得归内容审核域
Oct 20, 2026
2da024f
fix(upstream): 收窄 11140 的限流排除项,并纠正过时的「换号不换通道」注释
Oct 20, 2026
311c617
feat(server): 6021 queue.full 的 503 响应透传上游 Retry-After(issue #184)
Oct 20, 2026
33f2a33
go下载源改为国内源
pengyouak Oct 19, 2026
92c16fd
feat(upstream): 出站 DNS 可指定(dns_servers / WB2A_DNS)
yuanxing109 Oct 9, 2026
37f5939
feat(panel): 运行日志下新增「积分历史」,逐账号记录余额变动
Tinkler-i Oct 8, 2026
25378f5
feat(panel): 手机端适配(抽屉侧栏 + 宽表卡片化 + 窄屏时序图)
yuanxing109 Oct 9, 2026
9676e44
feat: 增加后台任务并修正计费与任务结果
Saito-Sakuya Oct 3, 2026
c5db9c4
fix(panel+server): 合并 #104 与分支语义——global 任务只读 + 计费口径分列判定
Oct 20, 2026
e32b43f
feat(upstream): 新增 WorkBuddy 联网搜索客户端
zcbxxx1 Oct 17, 2026
4369082
feat(server): 新增搜索端点 POST /v1/search/messages
zcbxxx1 Oct 17, 2026
c2b9801
feat(server): 搜索请求接入请求日志记账
zcbxxx1 Oct 17, 2026
1a77a2b
docs: README 补充搜索端点说明
zcbxxx1 Oct 17, 2026
b1afd25
fix(server): 搜索端点 review 修复(4 项)
zcbxxx1 Oct 17, 2026
1733564
fix(upstream): 企业额度 used 改为向上取整 + data:null 显式判空(issue #222 建议 1/3)
Oct 20, 2026
cf0ebb7
test: 同步企业额度取整方向变更的期望值(1188 → 1187)
Oct 20, 2026
654b55d
feat(server): 零 tool_calls 停摆检测与换号重试(issue #149)
Oct 20, 2026
9d93125
fix(upstream): 余额判空按「字段存在性」判定,并补齐个人口径与面板可观测性(issue #222 建议 3)
Oct 20, 2026
3927cbc
fix(panel): 静态 API Key 账号也要进积分历史(probe 缺 uid 被账本丢弃)
Oct 20, 2026
01884fe
fix(upstream): 企业额度字段按归一化键读取,消除「判空」与「取值」口径不一致
Oct 20, 2026
21d8114
fix(server): 零 tool_calls 停摆检测的换号重试必须真换号,且不得把模型答案变成 503
Oct 20, 2026
4934e6e
feat(panel): 停摆率可见——请求表挂「停摆」角标 + 统计条计数(issue #149)
Oct 20, 2026
fc2e28b
docs(config): 补齐新配置项的示例与说明(burn guard / 停摆重试)
Oct 20, 2026
1dff4d6
docs(readme): 补上本 fork 修复版的本地构建路径
Oct 20, 2026
6e0675f
chore(release): 版本号 1.13.0-panel → 1.13.1-panel(CI tag 断言要求 tag == 源码版本)
Oct 20, 2026
e9cddd0
feat(server): 接入 Codex Responses / Anthropic Messages 原生协议与官方检索透传
Oct 20, 2026
5ca18a4
fix(server): 搜索路径的在途租约用 defer 成对归还(错误/超时/ctx 取消/panic 全覆盖)
Oct 20, 2026
cd2684c
fix(auth): Windows 上 rename 失败必须降级原地覆盖,否则刷新后的 token 不落盘
Oct 20, 2026
bcd8ca4
fix(server): 流式停摆跳也必须排除在积分燃尽熔断之外(与非流式对称)
Oct 20, 2026
4f079fb
ci: 增加 Windows 专项测试 job,让 Windows 专属分支真正被执行
Oct 20, 2026
bb60e85
test(atomicfile): 把依赖 POSIX 目录权限的用例在 Windows 上显式跳过
Oct 20, 2026
fb7b179
fix(atomicfile): 并发写同一目标不得共用暂存文件名(Windows CI 首跑抓出)
Oct 20, 2026
4c633a3
fix(auth): 保存账号文件不得共用固定暂存名,否则并发刷新会静默丢内容
Oct 20, 2026
e786ef2
fix(server): 12153 与 scheduler 对齐为「连续 3 次才禁用」
Oct 20, 2026
1feb87d
fix(panel): 企业账号「跳过签到」不是错误,别再渲染成红色报错
Oct 20, 2026
098b80d
fix(pool): 402 硬冷却的到期时间跟上游时区走,别跟部署机器的本地时区
Oct 20, 2026
8332173
fix(upstream): 停摆判定自带「含原生工具调用标记 ⇒ 不是停摆」自防御;逐帧观察者可共存
Oct 20, 2026
d652498
fix(upstream): 企业额度解析的取值必须与遍历顺序无关,类型不匹配不能静默当 0
Oct 20, 2026
f0487f0
test(pool): 402 冷却到期时刻的断言按上游时区看,别看部署机器的本地小时
Oct 20, 2026
10ca586
fix(atomicfile): rename 撞上「目标被另一个写者占用」时要重试,不能直接判失败
Oct 20, 2026
8003365
fix(upstream): 工具调用判读收成一套,避免聚合形态被当成「没调工具」
Oct 20, 2026
7a0bdb9
fix(upstream): 流式 SSE error 帧的分类必须带上 error.code
Oct 20, 2026
8d749ba
fix(upstream): 11-128 与 11140 的判据按「主文案 + 业务码」分流,惩罚强度按状态码分级
Oct 20, 2026
fd7d981
fix(pool): 积分燃尽熔断要在面板口径里体现,并可被「解冻」清除
Oct 20, 2026
57af6b6
fix(pool): 「额度未知」不等于「额度为 0」,否则新账号会被积分保底静默挡掉(审计 Q6.1)
Oct 20, 2026
c4a8063
fix(upstream): 逐帧观察者必须拿到**深拷贝**,否则「只读不改对象」的承诺只对同步读取成立(审计 Q5.3)
Oct 20, 2026
dab5f8e
fix(config): 配置写坏不许拖垮启动——留 .bak 备份 + 解析失败自动回退(审计 Q4.5)
Oct 20, 2026
1874ba9
fix(upstream): error 帧也必须深拷,逐帧观察者才真正拿到「上游原样」
Oct 20, 2026
ece049d
feat(upstream): 加 WB2A_DUMP_BODY 调试开关,打印入站/出站请求体
Oct 20, 2026
1bd9e4f
feat(upstream): dump 开关同时打印出站请求头
Oct 20, 2026
d243d03
feat(logging): 运行日志可落盘,Windows 上没有控制台也能查
Oct 21, 2026
3d19016
fix(upstream): 调试 body dump 截断 + 出站头 dump 补测试
Oct 21, 2026
6159d03
fix(panel): 后台任务状态与任务日志归档必须走 atomicfile(Windows 上 rename 必失败)
Oct 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/docker-ghcr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,35 @@ env:
IMAGE_NAME: ${{ github.repository }}

jobs:
test:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- run: go test ./...
- run: go vet ./...

# Windows 专项测试:Windows 与 POSIX 的错误码语义不同(ERROR_ACCESS_DENIED /
# ERROR_NOT_SAME_DEVICE vs EXDEV / EBUSY),而仓库**同时发布 Windows 二进制**
# → 只在 ubuntu 上跑测试会让 Windows 专属分支永远不被执行到。
test-windows:
runs-on: windows-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- run: go test ./...
- run: go vet ./...

build-and-publish:
needs: [test, test-windows]
runs-on: ubuntu-latest
permissions:
contents: read
Expand Down
17 changes: 16 additions & 1 deletion .github/workflows/go-binaries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,23 @@ jobs:
# ubuntu runner 自带 node → panel 包的 JS 运行时冒烟测试(TestAppJSTopLevelSmoke)会真实执行
- run: go test ./...

# Windows 专项测试:Windows 与 POSIX 的错误码语义不同(ERROR_ACCESS_DENIED /
# ERROR_NOT_SAME_DEVICE vs EXDEV / EBUSY),而仓库发布**包含 Windows 二进制**
# → 只在 ubuntu 上跑测试会让 Windows 专属分支永远不被执行到。
# 实测教训:internal/auth 的 rename 降级判据在 Windows 上恒为 false
# → 刷新后的 accessToken 不落盘(issue #226 修复的 Windows 侧缺口)。
test-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- run: go vet ./...
- run: go test ./...

build:
needs: test
needs: [test, test-windows]
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand Down
7 changes: 5 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
FROM golang:1.23-alpine AS build
WORKDIR /src
COPY go.mod ./
RUN go mod download
# 防止因为直接使用官方源导致下载失败
RUN go env -w GOPROXY=https://goproxy.cn,direct && \
go env GOPROXY && \
go mod download
COPY . .
# 一次编译全部二进制(工具进镜像,容器内可直接跑脚本)。全部 -trimpath -s -w。
RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /out/wb2api ./cmd/server \
Expand Down Expand Up @@ -32,4 +35,4 @@ USER app
EXPOSE 7863
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s \
CMD wget -qO- http://127.0.0.1:7863/healthz || exit 1
ENTRYPOINT ["/app/wb2api", "-config", "/app/config.json"]
ENTRYPOINT ["/app/wb2api", "-config", "/app/config.json"]
258 changes: 188 additions & 70 deletions README.md

Large diffs are not rendered by default.

60 changes: 60 additions & 0 deletions cmd/server/cn_chat_base_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package main

import (
"slices"
"testing"

"github.com/linguo2625469/workbuddy2api-panel/internal/upstream"
)

// 老配置(无 cn 段)必须保留内置 CN base,零回归。
func TestCNChatBaseDefaultKeepsBuiltin(t *testing.T) {
cfg, err := ParseConfig([]byte(`{}`))
if err != nil {
t.Fatalf("parse: %v", err)
}
up := upstream.New()
want := up.ChatBaseCN
applyCNChatBase(up, cfg)
if up.ChatBaseCN != want {
t.Fatalf("ChatBaseCN=%q want builtin %q", up.ChatBaseCN, want)
}
}

func TestCNChatBaseOverride(t *testing.T) {
cfg, err := ParseConfig([]byte(`{"cn":{"chat_base":"https://www.workbuddy.cn"}}`))
if err != nil {
t.Fatalf("parse: %v", err)
}
up := upstream.New()
applyCNChatBase(up, cfg)
if up.ChatBaseCN != "https://www.workbuddy.cn" {
t.Fatalf("ChatBaseCN=%q want override", up.ChatBaseCN)
}
// global base 不受 cn 覆盖影响。
if up.ChatBaseGlobal != "" {
t.Fatalf("ChatBaseGlobal=%q want untouched", up.ChatBaseGlobal)
}
}

// cn.chat_base 只在装配期生效,面板保存后若被改动须提示重启。
//
// 语义随 #104 改为「按与运行中配置的实际差异列出」:cn.chat_base 没变就不必
// 提示重启,变了就必须提示。
func TestCNChatBaseRequiresRestart(t *testing.T) {
current, err := ParseConfig([]byte(`{}`))
if err != nil {
t.Fatalf("parse current: %v", err)
}
next, err := ParseConfig([]byte(`{"cn":{"chat_base":"https://www.workbuddy.cn"}}`))
if err != nil {
t.Fatalf("parse next: %v", err)
}
if !slices.Contains(restartRequiredFields(current, next), "cn.chat_base") {
t.Fatal("cn.chat_base missing from restart-required fields")
}
// 没改动时不应提示(装配期字段的提示只在真的变了时出现)。
if slices.Contains(restartRequiredFields(current, current), "cn.chat_base") {
t.Fatal("cn.chat_base reported although unchanged")
}
}
Loading
Loading