Blizzard
fb3685532c
polish(admin): 补齐侧栏菜单缺失图标,全项统一对齐
...
之前 登录设置/语音设置/微信用户/订阅 四项无 ICON_MAP 条目→图标位空、与兄弟项不齐。
补齐 heroicons 描边风一致图标:登录设置=钥匙、语音设置=麦克风、微信用户=聊天气泡、
订阅=循环;删掉无对应路由的死条目 usage。现 17 条路由全有图标。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-22 13:34:28 +08:00
Blizzard
95f3781076
feat(admin): 模型配置加「编辑」按钮 + 语音默认提示改 deepseek-v4-flash
...
- ModelManager: 每行加「编辑」→ 载入表单就地改(api_key 留空=沿用现有密钥),
后端按 id 走更新而非新增;表单头/按钮随编辑态切换,带「取消」;省去删了重登记
- ModelsPage: 语音默认模型提示 deepseek-chat→deepseek-v4-flash(chat 2026/07/24 弃用)
注:语音模型实例已通过 admin API 从 deepseek-chat 热切到 deepseek-v4-flash(dispatcher
现读 v4-flash,无需重启)——验证了编辑/激活的 NATS 热更新链路。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-22 13:07:13 +08:00
Blizzard
aec7ad949c
feat(model): 工作模型与 JARVIS 语音模型分开配置 + 语音任务路由到快模型
...
模型配置加"用途"维度:工作主力(chat,要强)与 JARVIS 语音(voice,要快/低时延)各配各激活,
语音任务走语音模型池,未配置则透明回落工作模型——不影响现有功能。
- contract: ConfigKindVoice="voice" + Meta[model_profile]=voice(与 intent==report 同类路由)
- gateway: ServeConfig/broadcastActive 循环纳入 voice;submitVoiceTask 打 model_profile=voice 标记
- dispatcher: 第二个 llm.Pool(voicePool)吃 voice 配置热更新;board.useVoice 从 Meta 派生(含快照);
Orchestrator.agentPool(b) 按黑板选池——语音且语音池就绪→语音池,否则工作池;
agent 生成路径(graph/react/coordinator/compose)全改走 agentPool(b),报告/护栏/记忆固定工作池
- admin: 模型页三 Tab(工作主力/JARVIS语音/向量化),复用 ModelManager;api Kind 加 voice
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-22 11:39:17 +08:00
Blizzard
a28ae49b6a
refactor(voice): 语音配置改用新版 API Key 鉴权(弃旧版 appid+token)
...
用户提醒:火山新版走 API Key 鉴权,不用旧版 appid+access_token。新版 WS 握手只带两个
header——Authorization(Bearer <APIKey>) + X-Api-Resource-Id。
配置从 {appid, access_token, 2×resource-id, voice} 收敛为 {api_key, 2×resource-id,
voice}:APIKey 走 secrets AES 加密入库;ASREnabled/TTSEnabled 改为只看 api_key+对应
resource-id。admin 配置页两个字段并一个 API Key 字段,清单同步改为新版口径。build+tsc 绿。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-21 17:06:22 +08:00
Blizzard
618184689e
feat(voice): 语音配置控制面——火山豆包 appid/token/resource-id/音色(参数落地处)
...
JARVIS 不依赖火山账号能先做的第二块:配置层,做成'你参数一填就落库'的形态。
- voice.Config: AppID/AccessToken/ASRResourceID/TTSResourceID/TTSVoiceType,AccessToken
走 secrets AES 加密入库(镜像微信配置);ASREnabled/TTSEnabled 可各自独立判断。
- admin GET/PUT /admin/voice(RequireAdmin),token 空串=沿用已存、明文回显。
- admin「语音设置」页(运维组):五个字段 + ASR/TTS 就绪徽标 + '去哪拿参数'清单。
端点/音频格式(PCM 16k 单声道)由代码固定不入配置。WS 会话 + 火山 ASR/TTS 客户端等
用户回传 resource-id 后按官方 demo 协议做。build+tsc 绿。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-21 17:00:35 +08:00
Blizzard
9b153871eb
feat(monitor): NATS 集群 Raft 副本健康 + 基建 ping 延迟(监测组完善)
...
此前 /status 把 NATS 当一盏二元灯(连不上就 fatal 故恒真),看不出 3 节点集群里
哪个节点掉了、JetStream 持久流的 Raft 副本是否还齐(计费/状态/评测流不丢的关键)。
DB/Redis/MinIO 也只二元 ping、无延迟。
- bus.ClusterStatus:连的节点名 + 集群发现节点数(nc.Servers) + RTT(nc.RTT) + 6 条关键
持久流(tasks/status/usage/eval/ingest/approvals)的 Raft 副本健康(leader + healthy/total,
单节点部署记 1/1;某节点掉队 → healthy<total 记降级)。
- /status 新增 nats 集群对象 + NATS 灯改为'连接且无副本降级才绿'、detail 显示'N 节点·连 X·
流副本齐全/降级'、latency=RTT;PG/Redis/MinIO 加 ping 往返耗时。
- admin StatusPage:新增 NATS 集群面板(节点/RTT/连接 + 各流 leader/副本健康/消息数表),
基建行显示延迟。
sundynix-shared/gateway build+vet+test 绿;admin tsc 绿。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-21 16:15:22 +08:00
Blizzard
83269e067a
feat(wechat): 关注公众号后自动回复欢迎语(被动回复,可后台配置)
...
用户关注服务号(扫登录码后关注 或 直接搜索关注)时,在回调 HTTP 响应里
回一条文本消息(微信「被动回复」)。被动回复不需要 access_token、不受 IP 白名单
限制,永远能发。欢迎语在管理端「登录设置」可配,留空用默认。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-21 11:17:41 +08:00
Blizzard
0f2afdaac1
feat(admin): 微信用户观测页 + 唯一昵称 + 密钥明文回显(单管理员后台)
...
按需求四项:
1. 微信新用户昵称改「微信用户_XXXXX」:后缀从 openid 的 sha1 派生(去混淆字母表),
openid 唯一 → 后缀实际不重复,且同 openid 每次一致(重登不换名)。用户可自行改名。
2. 后台加「平台 → 微信用户」列表:昵称 / openid(点击复制)/ 积分余额 / 加入时间。
每人仍独立租户与积分(各买各的,确认过不共享积分池),此页只做统一观测。
3. 登录设置的 AppSecret 明文回显(不再只显示"已保存")。
4. 支付配置的 APIv3 密钥明文回显。
—— 用户明确后台单人使用、RequireAdmin 已拦,接受这一安全降级;密文仍加密入库。
修一个 gorm Scan 坑:WechatUserRow 的 WechatOpenID/BalanceMicro 没加 column tag,
gorm 把 WechatOpenID 断成列名 wechat_open_id,与 SQL alias wechat_openid 对不上 →
openid 静默返回空。教训:Scan 到自定义结构 + SQL 用 alias 时,字段一律显式加 column tag。
本地验证:真库造两个微信用户,列表接口正确返回 openid(修 tag 前是空);
登录设置页 AppSecret 已是可见文本框;nickname 单测覆盖唯一/稳定/去混淆。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-21 10:36:27 +08:00
Blizzard
04b5677605
feat(site): 官网直接登录 + 购买(不再单独部署 Web 面)
...
用户要求「直接在官网登录,别多搞一个 web 工程」。官网本就是 admin 前端的一部分
(embed 进 gateway),在它上面加登录 + 购买,仍是「一个前端」,零新增部署。
sundynix-web(薄 Web 面)不部署;账单/组织/团队等留桌面端。
定价页「购买」流程:
未登录 → 弹微信扫码登录(带参二维码 + 关注/扫码事件)→ 登录后自动继续那笔购买
已登录 → 直接弹微信支付二维码 → 轮询单态 → 到账
支付走后端现有链路(下单/回调/查单/掉单补偿全复用),与桌面端同一套。
站点用户 token 存独立 key(sdx_site_token),与运维后台的 sdx_admin_token
隔开——普通用户登录拿到的用户 JWT 不该与管理员令牌混用。
本地验证:未登录点购买 → 弹登录弹窗;未配微信时如实显示「微信登录未配置」
(部署配好即真二维码)。登录门 + 支付弹窗 UI 骨架与错误态均正确;真二维码/
真支付留待部署后。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-21 09:23:23 +08:00
Blizzard
883540bd7e
feat(auth): 微信扫码登录改为「带参二维码 + 关注/扫码事件」(登录即涨粉)
...
上一版做成了网页授权(OAuth 允许页),方向错了。改成用户要的流程:
扫码 → 弹公众号关注页 → 关注即登录,服务号顺带涨粉。
流程:PC 建票 → 后端用 access_token 调「带参数二维码」接口(scene=ticket) →
展示微信二维码图 → 用户扫码关注 → 微信推 subscribe/SCAN 事件到 /wx/mp/callback →
按 openid 找/建用户 → ticket 置 authorized → PC 轮询拿 JWT。
明文模式(消息加解密):回调只验签名 sha1(sort(token,ts,nonce)),不做 AES。
关键实现点:
- access_token 缓存进 Redis(跨实例共享,避免重复拉取互相失效)+ 进程内锁双检;
- 事件同时处理 subscribe(未关注,EventKey 带 qrscene_ 前缀)与 SCAN(已关注,不带);
- 事件回调必须验签——否则任何人 POST 一个 openid 就能登录别人;
- 回调无论如何回 "success",否则微信重试并给用户弹"公众号故障";
- User.wechat_openid 用部分唯一索引(WHERE <> ''),避开存量空串互撞。
配置(appid/secret/token)后台可改、secret AES 加密入库。管理端「运维 → 登录设置」
列出还需在公众平台做的事(服务器 URL / Token 一致 / 明文模式 / IP 白名单)。
本地验证(真流程,非 mock):验签回 echostr 与微信算法一致;模拟 subscribe 事件
→ 建号 + 置票 → PC 轮询拿到 token+user → 库里确有该 openid 用户。真微信推真事件
留待部署后扫码。前端 web 登录页加「微信扫码/邮箱」双 tab,默认微信。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-21 08:58:31 +08:00
Blizzard
b1fea23a0c
feat(site): 官网定价页 —— 套餐由后台配置驱动,公开可见
...
官网加「定价」菜单与页面。数据来自 GET /api/v1/pricing(**不挂鉴权**):
运营改价、上下架、调发放节奏都在管理端完成,官网跟着变,不用发版;
未登录就能看到价格,这是转化的前提,也是官网存在的意义。
接口只吐在售项与展示字段,成本、权重、租户信息一律不出去。
结账仍在 Web 面完成(那里有登录态、租户上下文与支付轮询),官网只负责
「看价 → 去买」。同一套支付流程不在两处各实现一遍——这也是本次订阅开发
一直遵循的那条线:积分包与订阅共用一个支付弹窗,桌面端不重复购买入口。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-20 16:59:58 +08:00
Blizzard
f8f7359723
feat(admin): 订阅管理页 + 修「余额列为 NULL 导致充值永不到账」
...
管理端「支付 → 订阅」:套餐配置 + 全平台订阅观测。配置时直接算出「一个周期
发几次、合计多少积分」,时长不能被间隔整除时橙字提示到期前会有空档 —— 让人在
配的时候就看见后果,而不是上线后才发现只发了一次。
顺带修了个真 bug,是拿真库验订阅时撞出来的(本地 42 个租户里 11 个中招):
credit_balance_micro 是后加的列,早于它创建的租户行值为 NULL。而入账语句是
「余额 + N」—— SQL 里 NULL + N 仍是 NULL,于是这些租户**充值永远不到账**:
分录照写、余额不动、不报错。这条路径是充值/兑换码/退款/扣费/订阅发放共用的,
不是订阅引入的问题。
三处修:
- 5 处余额增减一律改 coalesce(credit_balance_micro, 0),新写入自愈;
- 启动迁移回填存量 NULL(按账本求和,让「余额 = SUM(ledger)」重新成立);
- 模型只加 default:0,**刻意不加 not null** —— 存量库有 NULL 行,AutoMigrate
尝试 SET NOT NULL 会直接失败,而且它在回填之前跑,等于把部署搞挂。
回归测试先证明能失败(去掉 coalesce → 余额 0)再确认修复。第一版测试因为我给
模型加了 not null 而无法造出 NULL,恰好暴露了上面那个部署风险。
真库验证:回填后 42 个租户 0 个 NULL;那个"有分录但余额 NULL"的租户余额
2981 = 账本合计 2981.34。管理端页面显示真实订阅(已发放 3 次 = 首笔 + 补发 2 笔)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-20 16:28:32 +08:00
Blizzard
466959d3c3
fix: 静默吞错横扫 —— 数据落库/配置广播/审计失败不再无声
...
把检索链路那次的做法推到同类位置。判据是"丢了这个 error 的代价",只改代价
高的,不动刻意的 fire-and-forget。
改(丢了就是数据永久丢失或行为不可解释):
- task_handler: 任务**输出**与**执行轨迹**的收尾落库。这是唯一的持久副本
(Redis 流 10min TTL),失败则永远无法复盘,界面上只显示"这次运行没有
轨迹"。轨迹的 json.Marshal 失败分支同样是静默跳过,一并补上。
- admin.broadcastActive: 模型配置热更新广播。失败 = dispatcher/mcp-go 仍用
旧配置,症状是"控制台改了模型却不生效",而操作者这边一切正常——正是今天
排查半天的那类问题。
- middleware/audit: 审计留痕写入。不阻断主流程是对的(业务已完成),但静默
失败意味着敏感操作没有记录,且没人知道记录缺了,这是合规缺口。
不改(确认过是合理的):
- dispatcher 的 PublishToken/PublishExec:往前端推流,丢一帧是 UI 瑕疵,
且按 token 打日志会刷屏;
- 计量回写 PublishUsage:本来就检查 error 并打日志,钱的路径是干净的。
另修一处误导文案:任务下钻的轨迹空态原本把原因说死为"早于该功能上线",
现在"落库失败"也是已知原因,文案改为并列并指向日志里的 [task] 告警。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-20 15:49:13 +08:00
Blizzard
518cddbd1c
feat(admin): 检索试验台分路卡片直接说明"为什么空"
...
此前四张卡片一律写"这一路没召回",而人的视线落在卡片上、不在顶部状态行。
现在按该路诊断分别显示:未启用给出缺什么配置(琥珀)、报错给出错误原文(红)、
真没匹配才说没召回。
真环境验证(截图为证):向量="该知识库在 Milvus 中没有向量(未入库或集合被
重建过)"、图谱="未启用:Neo4j 未连接或未配置"、全文="索引里确实没有匹配内容"。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-20 15:29:04 +08:00
Blizzard
b26fe21408
fix(rag): 检索三路不再静默吞错 —— 逐路诊断 + 一路挂不拖垮全部
...
排查"向量路为什么是空的"花了半小时,因为空就是空,没有任何线索。这次把
整条检索链上的静默降级一次清掉。
真 bug(不只是可观测性):
- kb_search 与 Search() 都拿 rag.Ready() 当总闸,而 Ready() 只代表"向量路
可用"(embedding + Milvus)。全文(bleve)与图谱(Neo4j)根本不依赖它们,却
被一并毙掉 → "模型配置没下发"表现为"整个知识库什么都搜不到",还不报错。
改为逐路判定,任一路可用就仍有召回。
不再吞错:
- milvus.search 原先把 error 转成 nil,nil —— 检索失败与无召回彻底无法区分;
- bleve.search / graph.search 出错直接回 nil,连日志都没有;
- searchPaths 丢掉 embedding 的 error。
三处改为如实返回,错误统一打日志。
逐路诊断(RouteDiag):每路上报 ok/empty/disabled/error + 耗时 + 原因,经
kb_search 的 diag 参数(仅试验台传,生产调用返回值不变)→ gateway → 检索
试验台。界面上现在能直接看出"这一路没配置/报错了/确实没匹配",不必翻日志。
内存兜底索引也会在 note 里点明"重启即清零"。
测试:3 组,覆盖"无 embedding 时全文仍可召回"、三种空的区分、内存索引提示。
把总闸加回去验证过第一条确实会红——测试能抓到这个回归,不是摆设。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-20 15:10:03 +08:00
Blizzard
00ad6c8ac0
fix(admin): 任务下钻按真实轨迹字段渲染 + 修评测页白屏
...
docker 起来后拿真库验证,上一版有两处只有真数据才暴露的问题:
1. 轨迹字段名猜错了。实际是 seq/ts/node/kind/phase/label/detail,我写的是
type/msg/at。更糟的是兜底判断用了 !e.msg && !e.node —— node 恰好存在,
兜底不触发,结果会渲染出一列几乎空白的行。现按真实字段渲染:label 作
标题、detail 作正文、kind 上色(system/model/tool/agent/plan/section/
render/approval 八种)、phase=error 整行标红、ts 转本地时间。
2. 评测页签点开直接白屏。库里 flags 存的是字符串 "null"(不是 "[]"),
JSON.parse 出来是 null,flags.length 抛 TypeError 把整个控制台打崩。
`as string[]` 的类型断言骗过了 tsc,单测也覆盖不到——只有点开真数据的
页面才会炸。改为 Array.isArray 校验。
验证方式:本地起 gateway + 真 Postgres,浏览器里逐个页签点过(轨迹 15 条
真实事件、最终输出、评测 100/100/100、DSL 格式化),并在真库上确认跨租户
读取、jsonb ->> 取 topic、cast(jsonb as text) 取 graph 均正常。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-20 14:20:58 +08:00
Blizzard
e4ec74893f
feat(admin): 任务观测支持下钻 —— 轨迹/输出/评测/DSL
...
全平台任务页此前只能看列表,点进去什么都没有。现在点一行开抽屉,四个页签:
执行轨迹、最终输出、评测明细、提交时的 DSL。不含审批操作——审批是客户端
用户的行为(桌面端 ApprovalBar),管理端只做观测。
不复用用户面的 /tasks/:id/replay:Task/Eval 都在租户插件作用域内,用请求 ctx
查别的租户的任务不会报错,而是静默返回空输出/空轨迹,UI 上表现为"这任务没
产出",比报错难查得多。新增 admin 端点走 WithoutTenant。
数据取自 sundynix_task 收尾落库的 output/trace 列,不依赖 Redis 流(10min TTL)。
所以这是复盘视图,运行中的任务轨迹为空——UI 里明确写出来,免得被当成轨迹丢了。
修的两处与测试环境失真有关(写测试时暴露的):
- 测试库没配 NamingStrategy,与 OpenPostgres 不一致:多数模型有显式
TableName() 碰巧对得上,但 Task 这类没有的会退化成 "tasks",导致写裸
SQL 的查询在测试里查无此表。现已对齐 sundynix_ 前缀 + 单数表名。
- graph 的 ::text 换成标准 cast(... as text):前者是 Postgres 专有,
换掉后这条查询才能被内存库覆盖。
新增 5 组测试,其中一组专门先证明"租户过滤在测试环境里确实开着"——否则
"跨租户能读到"的断言可能只是因为插件没装,属于假过。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-20 14:07:02 +08:00
Blizzard
84463394d4
fix(admin): 审计筛选下沉 SQL + 工具数不再写死 + 模型删除加确认
...
清单里那批小毛病,逐条复核后修(「审计详情列缺失」那条已不成立,早补上了)。
1. 审计筛选只在当前页生效 —— 影响最大的一条。分页是服务端的,筛选却在
前端对已取回的 50 条做,于是搜一个用户 ID 显示"无结果"时,后面几页
可能还有几百条。审计的用途就是查证,"搜不到"会被读成"没发生过"。
改为 action/path/q 三个条件全部落到 SQL,前端只管发条件(防抖 300ms)。
2. 服务状态页把 mcp-go/mcp-py 的工具数写死成 23/4 —— 增删工具后一直骗人,
且服务离线时照样显示,看不出工具其实一个都没注册上。改取实际上报值。
3. 模型删除一点即删,无任何确认。补二次确认,并对"正在使用中"的模型
单独说明后果(删掉会立刻打断线上对话/向量能力)。
审计筛选补了 4 组回归测试,两条是踩出来的坑:
- q 的 OR 组必须带括号:gorm 以 AND 拼接各 Where,裸 OR 会让 action
条件被绕过(测试里用"同 IP 不同方法"两行钉死这个语义);
- LIKE 必须显式写 ESCAPE '\':Postgres 默认拿反斜杠当转义符,SQLite
不写就没有转义符——原来的写法在单测里静默失效,搜 "100%" 命中 0 条。
顺带把 ILIKE 换成 LOWER()+LIKE,这段才能被内存库覆盖。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-20 13:51:59 +08:00
Blizzard
bfd0d74c34
feat(status): 全文索引降级上报到控制台 —— 让静默降级看得见
...
上一个提交修的是"卷没挂"这个实例,这个提交修的是"它坏了几周没人发现"这个
类别问题:全文路退内存兜底后,混合检索只表现为召回变差,不报错、无告警。
- mcp-go: bleveStore 记录 persistent;health 工具多报一个 fulltext_disk。
仍是 map[string]bool,gateway 现有反序列化不受影响(加非 bool 字段会让
整个 health 解析失败,连带 Milvus/Neo4j 健康灯一起黑)。
- gateway: 基建灯新增「全文索引」一项,退内存时给出后果与排查方向,
而不只是一盏灰灯。
- admin: 基建列表此前只渲染 name/up,detail 字段一直没露出——而降级原因
恰恰只存在于 detail 里。补上渲染(离线态用琥珀色),并给「全文索引」
补 INFRA_META(它不是独立服务,没有端口,落在容器卷上)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-20 13:44:48 +08:00
Blizzard
2c9ecc833e
feat(admin): 积分包支持就地生成付款码,验证支付链路
...
管理端「支付 · 配置 → 积分包」每行加「生成付款码」:下单 → 二维码 → 盯到终态,
用来确认「渠道配置 → 下单 → 扫码 → 回调/查单 → 幂等入账 → 积分到账」在当前
环境真的通。
刻意走用户面的 /api/v1/billing/*,不做 admin 专用旁路 —— 造条测试专线的话,
验过了也不能说明线上用户那条路通。租户由服务端按登录用户解析,无需带租户头。
代价是这会真实扣款,所以:
- 弹窗顶部显著提示是真单、会真扣钱,并指向「订单与对账」的退款入口;
- 已下架的包按钮禁用(服务端本就会拒,别让人白扫)。
弹窗展示订单号/状态/轮询次数/到账积分,出问题时能直接判断卡在哪一环,
比只说一句"成功/失败"有用。轮询策略与 sundynix-web 支付弹窗保持一致:
递归 setTimeout、切后台暂停、失败指数退避、倒计时以服务端 expires_at 为准。
依赖:admin 新增 qrcode(懒加载进 PaymentConfigPage 分块,不进主包)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-20 12:52:24 +08:00
Blizzard
34500e66a7
fix(admin): 补全 package-lock,修 CI 里 npm ci 失败
...
vitest@4 依赖 esbuild 0.28.x,而 vite@5.4 用 0.21.5,lock 里只写了后者,
vitest 那份嵌套 esbuild(含各平台包)从没落进 lock —— 当初加 vitest 时 lock
只做了部分更新。本地 node_modules 早已装好,npm run build / vitest 一直正常,
所以直到 Docker 里 npm ci 严格按 lock 装才炸:
npm error `npm ci` can only install packages when your package.json and
package-lock.json are in sync. Missing: esbuild@0.28 .1 from lock file
npm install 重新生成 lock,两套 esbuild 及其 linux/musl 平台包都已就位;
干净目录 npm ci 验证通过。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-20 11:25:26 +08:00
Blizzard
79b110afd0
feat(admin): 数据源页转 RAG 运维台 + 支付/模型菜单重组 + 概览升级为仪表盘
...
后端:
- 新增 POST /admin/kb/search:管理端跨租户检索,支持 mode 指定单路
(vector/fulltext/graph/hybrid),不走 scopedKB(否则会被强制锁到调用者
自己的 space,跨租户排障就没法做了)
- KB 清单补 space_id(检索键是 <space_id>/<name>,缺它前端拼不出 key)
前端:
- 数据源&RAG 页补「检索试验台」:同一 query 并排跑生产链路 + 四路诊断,
召回不准时能直接定位是向量/分词/图谱哪一环挂了
- 支付拆成「配置 / 订单与对账」两个子页,挂到运维 > 支付 下;
导航支持二级菜单(NavParent 命中子路由自动展开)
- SettingsPage → ModelConfigPage「模型配置」,模型参数与计费规则合一
- 概览 → 仪表盘:并入计费与用量(UsagePage → UsageSection),
去掉系统健康拓扑(与服务状态页重复,同一份 /admin/status 数据)
- 全局隐藏滚动条(保留滚动)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-20 11:17:54 +08:00
Blizzard
c3151d1078
refactor(admin): 配置按域收口到「系统配置」页,Usage 只留用量观测
...
原本模型配置在「模型」页、计费规则与支付渠道却塞在「分析 > 计费&用量」观测页里(该页
~1290 行,首屏全是表单、真正的用量观测在第四屏)。按「域」重组:
- 新建「系统配置」页,两个 Tab:
· 模型 = 模型登记/激活/连通性测试 + 计费规则(汇率/硬拦截/按模型定价与权重)
· 支付 = 支付渠道配置(兑换码/积分包/微信参数) + 订单流水(订单流/对账/人工退款)
配了什么就在同处看它的规则与数据,不用来回跳。三块直接复用原组件,零重写。
- 「计费 & 用量」瘦成纯用量观测(消耗趋势/租户排行/发放积分)。
- 导航「模型」页并入系统配置(12 页 → 11),侧栏图标换齿轮。
- 顺带修残留 bug:数据源页「前往模型管理」原为 href=#/models + onClick 改 hash,
既指向已废弃路径、又是 hash 写法(早已换 BrowserRouter,点了不跳),改正规 <Link to=/admin/settings>。
tsc + build + vitest 41 过。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-20 10:19:32 +08:00
Blizzard
d189dd967a
fix(admin): resolve JSX namespace and className syntax compilation errors in admin console
2026-07-18 22:21:13 +08:00
Blizzard
0d2929931f
feat(admin): upgrade admin console UI widgets, add plan & status management, and redesign system status dashboard
2026-07-18 22:18:12 +08:00
Blizzard
197531ea33
fix(site): 官网页头去掉深浅切换按钮(未挂 ThemeProvider 会运行时报错)
...
ThemeToggle 依赖 useTheme/ThemeProvider,但按'官网默认浅色'计划没搬那套 provider →
useTheme must be used within ThemeProvider 运行时崩。删掉切换按钮 + 无用的 theme-provider.tsx。
顺带 index.html 换中性标题 + favicon 指向官网 logo。排查确认无其它 Context/Provider 依赖、
logo 路径 /brand/ 正确。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-18 17:44:43 +08:00
Blizzard
6de1b3f6b2
feat(admin): 官网落地页融进 admin —— / 是官网、/admin 是运维后台
...
用户要 agent.sundynix.cn/ 打开是营销官网、/admin 是后台,且只用一个前端。
把 sundynix-site/web 的营销落地页融进 sundynix-admin 这一个 Vite 工程(不挂两份 embed):
- 拷官网到 src/site/:home(hero/功能/架构/快速上手/下载)+layout(header/footer)
+terminal-demo/logo/reveal 等 + content/site.ts(文案本就是本产品)。去掉博客/posts/埋点/RSS
(营销 only,零后端改动);use-release 改纯静态版本号。public/ 加 brand logo+favicon。
- Tailwind v4→v3 对齐:site 的 ink/ground/accent/term 等 token 加进 tailwind.config(var 引用)
+ :root/.dark 变量+keyframes 进 index.css;bg-ground/85 用 color-mix 还原。admin 自身用默认
gray/violet 调色板,不冲突;landing 的 bg-ground 只作用在 SiteLayout 容器、不改 body。
- 路由重构:App.tsx 换 BrowserRouter —— / 官网(公开)、/admin/* 后台(AdminGate 内做 me/Login/AppShell)。
routes.tsx path 改相对、AppShell 链接加 /admin 前缀。@ 别名指向 src/site。
- gateway/Dockerfile/nginx 零改动:单份 dist 挂根 + NoRoute SPA 兜底已支持 BrowserRouter 深链。
验证:tsc + vite build(Tailwind 编译过)+ vitest 41 过;gateway 二进制冒烟打真 serve——
/ 返回官网 index.html、/admin 与 /admin/tasks SPA 兜底 200、/brand/*.webp 200、/api/v1 走 API 401;
dist 里确认落地页文案已进 bundle。(注:MCP 浏览器当前断开,视觉渲染待部署后线上看。)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-18 17:36:43 +08:00
Blizzard
373167b705
feat(admin): 补全平台任务观测 + 空间管理 + 基建加 MinIO/实时探针
...
对照已实现系统功能补 admin 缺失模块(feat/site):
- 全平台任务/运行观测:GET /admin/tasks(跨租户查 sundynix_task,join 租户名/提交人邮箱/评测,
按状态/租户筛 + 状态计数;含 HITL 待审批=筛 waiting)+ TasksPage(状态卡+筛+表)。
- 空间(Space)管理:GET /admin/spaces(跨租户列 Space + 成员数子查询 + kind/归档态)+ SpacesPage。
- 基建观测:infra 加 MinIO(126 对象存储);postgres/redis/minio 从启动标志升级为实时 ping
(blob.Ping/Postgres.Ping/Redis.Ping),能反映中途掉线。StatusPage 加 minio 标签、6 个依赖。
- 模型健康/熔断:确认 DashboardPage 已有「运行时链路态」渲染 m.health,无需重做。
验证:admin tsc + vitest 41 过、gateway build/vet/test 过;两新页浏览器实测渲染+优雅错误处理;
两新端点起临时 gateway 打真 PG 实测——tasks(counts+3路join)、spaces(成员数子查询)均返真数据。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-18 17:06:25 +08:00
Blizzard
5e5f6e9610
feat(billing): 人工退款入口 —— paid 单冲销积分+置 refunded(幂等)
...
PAYMENT_DESIGN §5 承诺却只留了 OrderRefunded 常量、无入口。补齐全链路:
- store.RefundOrder:订单 CAS(paid→refunded) 为主闸(重复退 changed=false 幂等),
同事务记 adjust 负分录(ref=订单号)+ 回退物化余额。照抄 MarkOrderPaid 双闸范式;
新增 idx_ledger_refund_ref 部分唯一索引(kind='adjust' AND ref<>'')做账本级兜底,
与 grant 索引对称、不与 admin 手工校正(ref 空)冲突。
- 积分若已消费,回退后余额可为负(人工退款预期,账本仍自洽,后续消费被硬拦截)。
- handler AdminRefundOrder + POST /admin/orders/:id/refund(admin 组已挂 Audit 留痕);
真渠道钱款原路退回需 admin 另在商户后台操作,本地仅冲销积分与订单态(不接自动退款 API)。
- admin 订单流加「退款」按钮(仅 paid 单可见,二次确认+填原因)。
- 测试:RefundOrder 冲销+幂等、只退 paid 两个不变量测试(sqlite 真 DB,余额=账本之和)。
gateway build/vet/test 全绿,admin tsc 干净。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-18 13:35:31 +08:00
Blizzard
e29bc9a91e
feat(admin): 「数据源 & RAG」页做实 —— admin 三 mock 页清零 (P1)
...
审计 P1「admin 三页纯 mock」最后一页。此前 DatasourcesPage 的 GraphRAG 拓扑图
写死节点、「向量/全文/图谱权重滑块」纯 mock——而且权重概念本身虚构:mcp-go 的
RRF 融合是各路等权的倒排互惠融合(rrfK=60 平滑常数),根本没有"每路占几成"。
- store/datasource_query.go:AllDatasources(全平台 KB + 各库文档数/总字数,
按 (space_id,name) 关联 doc,WithoutTenant);GET /admin/datasources(含
SystemCounts 平台计数)。
- DatasourcesPage 重写:保留真实 Embedding 模型配置(ModelManager) + 诚实的
混合检索管线说明(三路 Milvus/Bleve/Neo4j + RRF 等权融合 k=60,非可调权重) +
平台计数卡片 + 真知识库清单表。删假滑块+假拓扑(~200行 mock)。
诚实边界:RRF 无每路权重,不摆假滑块;检索参数在 mcp-go 代码中。
live:/admin/datasources 返 34用户/25库/53文档,清单带真实文档数字数;
浏览器渲染全对。tsc+41 vitest 全绿。**admin 三 mock 页(Evals/Guardrails/
Datasources)全部做实。**
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-18 12:26:16 +08:00
Blizzard
c02ebc7bce
feat(admin): 「安全护栏」页做实 —— 接真护栏事件,去 mock (P1)
...
审计 P1「admin 三页纯 mock」之二。此前 GuardrailsPage 是写死的正则/敏感词
编辑框(改了不生效的假配置)+编造拦截日志。后端 /admin/guardrail-events 早已
现成(T4.B),纯前端做实。
- 命中事件流接真数据(guardrail_event,middleware.Guardrail 命中即落库):
blocked 硬拦/suspect 灰区放行,带原因/信号/路径/来源;计数卡片+原因 Top 分布
(客户端从近100条聚合)+按 kind 筛。
- 诚实处理假配置:护栏规则(Tier1 正则/词库 + Tier2 LLM 分类器)是中间件代码
常量、非运行时可配,故删掉"能改却不生效"的编辑框,换成只读规则说明 + 指出
运行时可配需另建配置存储(参考提示词控制面)。不摆假控件。
live:触发注入越狱输入→422 硬拦+落库(reason「疑似提示词注入」)→页面渲染
真事件流+原因分布。tsc+41 vitest 全绿。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-18 12:07:32 +08:00
Blizzard
d04d830c37
feat(admin): 「自动评测」页做实 —— 接真评测数据,去 mock (P1)
...
审计 P1「admin 三页纯 mock」之一。此前 EvalsPage 是写死的质量趋势+编造的
错题本+虚构纠偏轨迹。现接 sundynix_eval 真数据(评测经 JetStream eval 流持久
落库,刚升级)。
- store/eval_query.go:EvalTrend(按天 avg 综合分/忠实度+低分计数)、EvalSummaryFor
(ok/warn/poor/corrected 计数+均值)、PoorEvals(错题本,level in poor/warn +
评语+纠偏标记+租户名)。全 WithoutTenant 平台口径;忠实度均值只算 sources>0
(无来源的忠实度恒0会压低失真)。
- GET /admin/evals?days=(RequireAdmin);admin api.ts + EvalsPage 重写:
总览卡片(综合分/合格率/低分占比/纠偏采纳率)+质量&忠实度趋势(纯SVG折线+低分
背景条)+错题本(点行展开评语)。
- 诚实边界:纠偏「前后全文对照」后端未持久化,只存了 Reason/Corrected/各维度分,
故错题本展示评语+「已纠偏」标记,不再编造 before/after。
live:/admin/evals 返 57 次评测 avg=0.88、错题本10条、11天趋势;浏览器渲染
真数据(趋势线07-15真实下探)。go+tsc+41 vitest 全绿。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-18 12:03:54 +08:00
Blizzard
a1c35852ef
chore: 删死代码 —— OpenReport/ReadLocalFile/isDesktop/openReport + admin Soon (P2)
...
完成度审计确认全链零生产调用:
- app.go OpenReport(仅被死包装引用)、ReadLocalFile(仅测试引用);
desktop.ts openReport 包装、isDesktop 导出(实际用 isMacDesktop)——全删。
绑定重新生成(OpenReport/ReadLocalFile 归零,PrintReportPage/SaveReportAs/
Notify 保留)。删对应的 app_test TestReadLocalFile。
- admin Soon.tsx(规划中占位组件)已成未引用死组件——routes.tsx 9 条路由全
ready:true,import 未用。删组件+import。
openInSystem/filepath/os 仍被 PrintReportPage/download 使用,不孤立。
desktop go test + tsc + 68 vitest、admin tsc + 41 vitest 全绿。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-18 11:56:51 +08:00
Blizzard
3db2de1ef6
feat(billing): 支付 P5.3 —— 掉单补偿定时器 + admin 订单流 + 日终对账
...
支付线封口。此前 pending 单只在「用户开着账单页轮询」时才查单确认——用户扫完码
关页面,钱付了、积分永不到账。
- 掉单补偿定时器(payment_reconcile.go):gateway 内每分钟扫 pending 微信单,
逐单 reconcileOrder 主动查单落态。把「用户在不在场」从入账链路摘掉。
reconcileOrder 从 BillingOrderStatus 抽出、前端轮询与定时器共用一份幂等
落态逻辑(不重蹈 GenerateReport/SubmitTask 的漂移)。渠道未配置时空转不炸。
- admin 订单流 GET /admin/orders(状态计数+全平台订单,可筛)。
- 日终对账 GET /admin/orders/reconcile:paid 单 ↔ 账本 grant 分录逐单比对,
抓 order_without_ledger(钱到了积分没给,最严重)/ ledger_without_paid_order。
- admin 计费页「充值订单与对账」块:计数卡片+订单流+一键对账。
⚠️ live 抓到并修掉一个真 bug:OrderStats 复用同一个 gorm.DB 链式 Count 三次,
WHERE 累加成 status=A AND status=B → 恒 0(订单流显示 2 单但计数全 0)。
改成每次起新 query builder。—— 又一次只有 live 才暴露的。
验证:go 6 包测试+tsc+41 vitest 全绿;live 造差异单对账正确抓出
order_without_ledger、清账后回零差异;补偿器启动日志+渠道未配置空转不炸;
浏览器验订单流卡片+一键对账绿条。TTL 过期路径需真渠道触发,部署后自然覆盖。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-18 11:25:37 +08:00
Blizzard
5d7eca5de3
fix(billing): 微信支付钉死「微信支付公钥」验签体系 —— 商户 2025-09 开户没有平台证书
...
用户拿旧项目代码对出来的真问题:我此前用 WithWechatPayAutoAuthCipher(平台证书
模式,APIv3 密钥自动下载平台证书验签),但 2024 起新注册商户只发「微信支付公钥」
(PUB_KEY_ID_ 开头)、没有平台证书——在该商户号上初始化/回调验签都会挂。
- 改 WithWechatPayPublicKeyAuthCipher(商户私钥+公钥ID+公钥文件);回调验签用
NewSHA256WithRSAPubkeyVerifier;平台证书模式不留双模式赘肉(YAGNI)。
- Config 增 public_key_path/public_key_id(必填,公钥文件同样只存路径);
admin 卡片补两字段;env 兜底加 WECHAT_PUBLIC_KEY(_ID)。
- 顺手修 live 撞出的真 bug:sundynix_setting.value 是 varchar(255),
支付配置 JSON(含加密密钥)一条就超(SQLSTATE 22001)→ 改 text。
live:列类型已迁 text;缺公钥两项报「配置不全,缺: public_key_path,
public_key_id」;GET 回显含新字段。go 6 包测试+tsc+41 vitest 全绿。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-17 11:12:26 +08:00
Blizzard
d1e1e0fc4a
feat(billing): 微信支付配置进 DB —— admin 控制面保存即热生效
...
用户定的形态:配置存数据库、密钥文件放服务器磁盘(库里只存路径)。
env 降级为兜底(DB 优先 → env → 隐藏,与 tokens_per_credit 同一约定)。
- payment 包重构:Config(6 字段)+ Manager(RWMutex 热重载,学 prompt 控制面
改完即生效不重启);未启用原因人话化(未配置/缺哪些字段/初始化失败具体错)。
- APIv3 密钥入库前 AES-GCM 加密(shared/secrets,与模型 API Key 同一把
SUNDYNIX_SECRET_KEY);GET 只回 has_apiv3_key 不回显;PUT 留空=沿用旧密钥
(只写不回显语义,同模型 Key)。
- admin GET/PUT /admin/payment/wechat;业务路径全部改经 Manager.Current()
取快照(BillingPacks/下单/查单/回调)。
- admin 计费页「微信支付配置」卡片:状态徽章(已启用/未启用+原因)+六字段
+保存并热生效。
live:无配置→「未配置」;存假配置→热重载报「私钥加载失败:decode err」;
去掉 appid→「配置不全,缺: appid」;密钥留空沿用(has_apiv3_key 保持 true);
psql 复核库内密文 enc:1: 前缀、不含明文子串。go/tsc/41 vitest 全绿。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-17 10:55:30 +08:00
Blizzard
929bbf334b
feat(admin): 计费页长出「充值渠道」块 —— 兑换码生成/台账 + 积分包定价
...
P5.1 收尾:此前生成码只有 API。计费页现在从上到下 = 计费规则(积分→token
汇率) → 充值渠道(钱→积分:兑换码 + 微信定价用的积分包) → 用量观测,
两层汇率在同一页可见、各管各的。
- 兑换码:面额/张数/备注生成;**明文码只在生成响应显示一次**(等同现金,
台账 GET /admin/redeem-codes 服务端脱敏只露首尾,丢码重生成、不提供找回
——顺手把接口这个第二明文出口堵了);台账含核销状态。
- 积分包:新增/上下架(微信 P5.2 上线前把定价面备好);admin api.ts 补
packs/redeem-codes 四个函数。
- launch.json 加 admin-console-alt(:5176)——5174 被用户自己的 sundynix-site
占着,不动别人端口。
live:5176 登录→生成 5 张(绿色一次性面板+复制全部)→配「入门包 1000分/¥9.9」
在售可下架→台账脱敏 curl 复核;tsc+41 vitest 全绿。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-17 10:28:03 +08:00
Blizzard
b388915fff
feat(admin): 租户页加「共享计费」开关(每租户)
...
TenantRow 带 shared_billing;选定租户成员区上方加共享计费开关(PUT
/admin/tenants/:id/shared-billing):开=成员消耗计本租户池、关=各计个人池。
live 验证:公司A 开关随真实状态回显为勾选。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-08 10:56:21 +08:00
Blizzard
aa10037511
feat(admin): 「租户 & 用户」页接真实成员管理(删掉 mock)
...
此前整页是硬编码 mock(假租户/假用户/假 API key/假日预算)。重写为真数据:
- 左:租户目录(listTenants:名称/slug/plan/成员数/积分余额)+ 建租户表单
(名称/slug/可选 owner 邮箱)。
- 右:选定租户成员表(listMembers)——按邮箱加成员+选角色、行内改角色、移除;
owner 受保护(不可改角色/移除)。api 加 listTenants/createTenant/listMembers/
addMember/setMemberRole/removeMember。
live 验证(preview):14 个真实租户带成员数/余额;UI 加 demoB→Dexter「2 成员」、
成员表 owner 保护 + 成员可改角色/移除、移除后回 1 成员,全过;tsc + 41 测试全过。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-08 10:20:11 +08:00
Blizzard
b46382817c
feat(admin): 计费页加「余额硬拦截」开关 + 各租户「充值」按钮
...
闭合积分环的配置/操作端,接到 P4 后端:
- 计费规则区:加「余额硬拦截」开关(credit_enforce),与汇率合成一个「保存规则」。
- 用量观测·租户排行:每行加「充值」按钮(正=充值、负=校正),调 /admin/credits/grant,
充值后即时刷新余额。
- api:getBillingConfig/saveBillingConfig 带 credit_enforce;新增 grantCredits。
live 验证(preview):开关渲染+可存;点公司A「充值 10」→余额 5.92→15.92、账本落对租户;
tsc + 41 vitest 全过。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-07 13:53:52 +08:00
Blizzard
11d321f218
feat(admin): 计费 & 用量合成一页 —— 顶部配规则、下方看结果(闭环)
...
按"配置和观测放一个页面"收口:删掉重复的「计价 & 预算」页(其预算区块是 mock),
把真·计价配置并入「计费 & 用量」,形成 规则→扣费→观测 一页闭环。
- 新组件 BillingRules:全局 token→积分汇率 + 每模型 单价/币种/积分权重(读写
/admin/pricing + /admin/billing-config),改完对后续任务实时生效。
- UsagePage:顶部「计费规则」(配置端) + 下方「用量观测」(按规则折算后的实际消耗)。
- 删 PricingPage + /pricing 路由;api 加 credit_weight / getBillingConfig / saveBillingConfig。
live 验证(preview):改汇率保存→持久化→新任务按新汇率扣→用量观测反映;
tsc + 41 vitest 全过;无 PricingPage 残引。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-07 13:26:33 +08:00
Blizzard
54de95aa53
feat(admin): 用量 & 计费页 —— SaaS P2 计量观测面(读 /admin/usage)
...
管理端「分析」组新增页:全平台 / 单租户的 token · 积分 · 成本口径。
- api.adminUsage():拉 /admin/usage(含 trend / totals / tenants 排行 / 单租户余额);
微单位(×10⁻⁶)前端 ÷1e6 展示。
- UsagePage:租户下拉 + 近7/30天切换;KPI 卡(积分/Token/成本/余额或活跃租户);
积分消耗按天条形趋势(补零连续);全平台口径下各租户排行表(点名下钻单租户)。
- routes 注册 /usage(HashRouter)。
live 验证(preview):全平台两租户排行 + KPI + 趋势条渲染正确;点租户下钻→
单租户口径 + 当前余额卡;数值与后端自洽;无 console 错误;tsc + 41 vitest 全过。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-07 12:38:33 +08:00
Blizzard
55d50417a9
feat: 模型健康/熔断态 surface 到管理端(T4.F 可观测)
...
failover/熔断的运行时态原来只在 dispatcher 日志、admin 看不到 —— 本次接到概览可见:
- harness: CircuitBreaker.Snapshot() 只读观测访问器(state + fails,不动状态机)
- llm: Pool.ModelHealth() 上报主备链每模型 {provider,model,role,state,fails};
buildWithFallbacks 把模型名↔breaker 配对(同包直接读 failoverModel.breakers);
newFailoverModel 改返回具体类型以便读 breakers
- dispatcher 心跳 payload 加 models[]
- gateway /admin/overview 独立超时 Ping dispatcher,合并进 models.health
- admin 概览「模型路由」新增「运行时链路态(实时)」:逐模型状态点
(🟢 在线/🔴 熔断中+失败数/🟡 半开探测/单点)
- 单测:Snapshot、Pool.ModelHealth(名字↔态配对/单点/空)
- live:配坏主→提交任务打熔断→概览显示 broken-demo「熔断中·失败3」,备用在线
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-06 12:00:13 +08:00
Blizzard
a830ae2a04
feat(admin): 审计 & 安全事件页(T4.B 收尾)
...
- 新增「审计 & 安全」页(/audit,运维组):接 /admin/audit + /admin/guardrail-events
- 安全事件:护栏拦截/灰区放行(kind 徽标 + 原因 + method/path + actor/ip/时间)
- 操作审计:变更操作(方法配色徽标 + 路径 + 状态码着色 + actor/ip/时间)
- 顶栏统计(操作留痕/护栏拦截/灰区) + 30s 自刷 + 手动刷新
- api.ts 增 listAudit / listGuardrailEvents + 类型
- 风格对齐重做后的服务状态页(中性克制)
- T4.B 整组完成(剩 HITL 审批明细可选小项)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-02 09:43:41 +08:00
Blizzard
30e80c0eed
feat(admin): 提示词控制面页 + 概览/状态页重做 + 接入 vitest
...
- 新增「提示词」页(/prompts):接 /api/v1/prompts,建版本/激活热下发/
对比激活版行级 diff/撤销,挂到配置组
- 概览页重做为系统控制塔:吃 admin/overview(全平台口径)——平台任务/
评测/用户规模/服务在线 + 模型路由态 + 提示词覆盖态 + 健康拓扑 + 30s自刷
- 服务状态页重做:中性克制风 + 请求链路做成深色实时数据管道(流动光点/
节点辉光) + MCP 工具改能力域配色小卡片
- 接入 vitest(此前零测试):41 单测(api 控制面/lib diff/路由派生)
- api.ts 增 statsOverview/adminOverview/prompt 控制面四接口 + groupPrompts
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-02 08:59:40 +08:00
Blizzard
2d9695e940
feat: admin端UI
2026-06-27 12:06:29 +08:00
Blizzard
a5fd251fc0
feat(deploy): 容器化 + 一键独立部署 —— 5 服务镜像 + prod compose + 安装/备份/许可
...
此前应用服务只是本机裸二进制、无 Dockerfile、无法交付。本提交把项目从"只能在我笔记本
跑"变成"任何人一条命令起一整套",是「演示 / 拉投资 / 卖给客户独立部署」的可交付基础。
- Dockerfile ×5:gateway/dispatcher/mcp-go 多阶段(distroless static, 36–55MB);
mcp-py(python-slim, 268MB);admin(node 构建→nginx 托管 SPA + 反代 /api,76MB)。
Go 构建上下文为仓库根以兜住 replace ../sundynix-shared;.dockerignore 瘦上下文。
- docker-compose.prod.yml:应用 + 基建一把起;经服务名互连(顺带避开 localhost DNS 坑);
基建端口不对宿主暴露;depends_on 健康检查保序(mcp-go 待 Milvus healthy);
APP_ENV=production 强制密钥校验 + 锁 CORS + 管理员白名单。
- .env.example + DEPLOY.md:两类密钥分层(引导密钥走 .env,模型 key 控制台加密存库);
首次管理员流程;安全建议。LICENSE 专有(授权模型可后定)。
- scripts/backup.sh + restore.sh:PG 逻辑备份 + 各数据卷快照 / 恢复。
- .gitignore 挡 .env*(密钥不入库)。
live:5 镜像全构建通过;独立 project 起整套 → nginx→gateway→NATS→dispatcher→mcp 全链路
注册+提任务 running→done,depends_on 保序生效。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-26 15:23:36 +08:00
Blizzard
075d41f5b3
feat(llm): 本地模型接入 vLLM / Ollama + reasoning 思考过程入轨迹
...
vLLM 与 Ollama 都暴露 OpenAI 兼容 API(底层 go-openai 请求 {base}/chat/completions),
故统一走 openai 客户端,按 provider 归一化连接参数:
- Ollama/vLLM 的 OpenAI 端点固定在 /v1,BaseURL 漏写自动补全(否则打到 /chat/completions 404)
- 本地后端默认不校验 api_key → 缺省补占位(ollama→"ollama",vllm→"EMPTY";openai 客户端要求非空)
- 显式 key 一律尊重(vLLM --api-key 启动);在线 provider 原样不动(DeepSeek 两种都收)
reasoning_content 适配:ChatStream 增 onReasoning 回调,捕获 reasoning 模型
(本地 Qwen3 思考 / DeepSeek-R1 / QwQ、在线 deepseek-v4-pro)的思考分片。思考阶段分片
Content 为空本就不污染答案;runAgent 把思考累计后 surface 到 exec 轨迹「推理过程」事件。
控制台 ModelManager 加 ollama 选项;llm 包补 normalizeBaseURL / apiKeyOrPlaceholder 单测。
四模块全绿。live:经 admin 配 ollama qwen2.5:0.5b → dispatcher 热切(日志 base 自动 .../v1)
→ POST /v1/chat/completions 200 端到端出答案;切回 deepseek-v4-pro → exec 轨迹现「推理过程:思考26字…」。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-26 11:10:18 +08:00
Blizzard
8bcb90cdb2
feat(admin): 服务状态面板(基建/服务探活 + MCP 工具注册)+ mcp-go 工具注册表
...
管理端新增「运维 › 服务状态」:总览横幅 + 摘要数字 + 请求链路拓扑
(客户端→网关→NATS→调度→MCP,按健康三态着色)+ 应用服务卡(含探针
延迟)+ 基建磁贴 + MCP 工具按能力域分组(中文名/作用)。
探活机制(全走 NATS,无 HTTP):
- mcp-go/mcp-py 新增 list_tools 自省工具,能应答=在线 + 上报工具清单
- dispatcher 无端点 → 新增 NATS 心跳主题 sundynix.health.dispatcher
(ServeHealth 应答 model/ready/uptime),网关用 bus.Ping 探
- 网关 GET /api/v1/admin/status 并发聚合四探针 + 各项延迟
mcp-go 重构:switch → map 注册表(buildRegistry),dispatch 与 list_tools
共用单一事实源,杜绝漂移;每个工具带中文名 + 作用描述。mcp-py 同样补元信息。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-22 16:38:10 +08:00
Blizzard
597665f3c8
feat(admin): 计价配置(按模型·分输入/输出单价)—— 计费比率配置落地
...
计费需 token↔真钱比率,配置归管理端。本次落地"按模型·分输入/输出"粒度:
后端(gateway):
- store.Pricing 模型(BaseModel + model_id 唯一 + input_per_1k/output_per_1k + currency),
AutoMigrate 建 sundynix_pricing;ListPricing/UpsertPricing(OnConflict model_id 覆盖)。
- admin handler:GET /admin/pricing 列表、PUT /admin/pricing 设置(校验非负,币种默认 CNY),
挂在 RequireAdmin 组下。
前端(admin):
- api:listPricing/savePricing(带 Bearer)。
- PricingPage:列出所有已登记模型(chat+embedding),每行可编辑 输入/输出每1K单价 + 币种,逐行保存。
- routes 新增「计价」页(配置组)。
实测:PUT→ok;GET 返回正确行;重复 PUT 同 model_id 仍 1 行且值更新(upsert 生效);表自动迁移。
前端 tsc 干净。下一步可做用量计量 × 单价折算(真正计费)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-19 11:25:24 +08:00