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
|
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
|
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
|
b98cf3c718
|
feat(gateway): 多租户增量2 —— 租户切换 + 每租户共享计费开关
用户可切活跃租户,消耗按"计费租户"扣(数据仍落活跃租户/工作区):
- User.active_tenant_id(切换持久化)+ Tenant.shared_billing(每租户开关,默认关)。
- 中间件 ActiveTenantForUser:active_tenant_id 若有效(仍是成员)则用之,否则默认租户。
- 计费目标解析 ResolveBillingTenantID:本人是活跃租户 owner 或该租户 shared_billing 开
→ 记活跃租户;否则记本人个人租户(各付各的)。SubmitTask 的硬拦截 + 用量都按它走。
- 接口:GET /me/tenants、POST /me/tenant(切换)、PUT /admin/tenants/:id/shared-billing;
/tenants/current 改显"可花余额"(计费租户) + billing_shared 标记。
live 验证(demoB 是公司A 成员、个人租户=公司B):切到公司A 后——
shared OFF:任务落公司A 工作区、用量扣公司B(个人),公司A 不变;
shared ON:用量扣公司A(共享),公司B 不变;/tenants/current 余额随之在 6.48↔15.92 切换。全过。
前端切换器 + admin 开关见后续。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
2026-07-08 10:52:17 +08:00 |
|
Blizzard
|
0e47a827c0
|
feat(gateway): 多成员租户·成员管理后端 —— 租户目录 + 成员增改删
真·多租户地基(此前只有单人默认租户 + admin 页是 mock):
- store:ListTenants(含成员数+余额) / MyTenants / ListMembers(join user) /
AddMemberByEmail(邮箱归一化小写、幂等 upsert、复活已移除、未注册报友好错) /
SetMemberRole(禁改 owner、禁直接授 owner) / RemoveMember(软移除、禁移除 owner) / ValidRole。
- admin 接口:GET/POST /admin/tenants、GET/POST /admin/tenants/:id/members、
PUT/DELETE /admin/tenants/:id/members/:uid。
live 验证:加 demoB 入公司A→member、列表、改角色→admin、移除 owner 被拒、移除 member,全过。
admin 前端接线 + 租户切换 见后续。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
2026-07-08 10:13:58 +08:00 |
|
Blizzard
|
93741a5504
|
feat(gateway): 闭合积分环 —— 充值/发放 + 提交前余额硬拦截(默认关)
让预付费积分成为闭环(发放→消耗→见底拦住):
- POST /admin/credits/grant:给租户充值/发放(正=grant,负=adjust 校正),
复用 store.GrantCredits(账本分录 + 物化余额,一事务)。
- 提交门控:credit_enforce 开启且租户余额≤0 → 拒绝新任务 402;默认关=软扣不拦。
开关入 billing-config(sundynix_setting KV,后台可切)。
- 修 bug:GrantCredits 是跨租户管理操作,须 store.WithoutTenant——否则 tenant 插件
会把账本分录的 tenant_id 覆盖成 admin 自己的租户(余额记目标、分录记 admin,破坏对账)。
live 验证:enforce 关→余额0可提交;开→余额0拒 402;充值后可提交、余额递减;
修复后 grant 分录落到目标租户、balance==SUM(ledger) 不变量成立。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
2026-07-07 13:53:43 +08:00 |
|
Blizzard
|
e2fc2d366c
|
feat(gateway): 计费规则可后台配置 —— token→积分汇率(DB) + 每模型积分权重
让「扣费按规则扣」的规则真正可后台热调(此前汇率是 env、积分权重无接口):
- sundynix_setting KV 表 + GetSetting/SetSetting;TokensPerCredit 改为
DB 设置优先 → env 回退 → 1000,SaveUsageEvent 按 ctx 读,改完即对后续任务生效。
- Pricing.credit_weight 纳入 UpsertPricing + ListPricing/SavePricing API。
- GET/PUT /admin/billing-config(token→积分汇率)。
live 验证:UI 存汇率=500 → billing-config/DB=500 → 新任务 credits_micro=214000
=107tok/500×1e6,规则→扣费联动精确成立。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
2026-07-07 13:26:20 +08:00 |
|
Blizzard
|
bf75bb8a62
|
feat(gateway): SaaS P2 计量·增量3 —— GET /admin/usage 用量/积分/成本口径
系统级(store.WithoutTenant,跨租户)用量观测:
- 无 tenant:全平台按天 SUM 趋势 + 各租户用量排行(含当前余额)。
- 有 tenant:该租户按天趋势 + 当前积分余额。
- from/to(YYYYMMDD)缺省近 30 天。UsageTrend/UsageByTenant/TenantBalance store 方法。
live 验证:两口径数值自洽(balance=seed−credits、credits=tok×汇率、totals=trend之和)。
至此 P2 计量后端(事实源)齐:明细/账本/余额/rollup/查询。前端页 + P4 硬拦截/充值待需求拉动。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
2026-07-07 11:42:21 +08:00 |
|
Blizzard
|
ee1e9cfdca
|
feat(gateway): 多租户2b-A —— Task 加 owner/tenant 隔离 + 系统旁路修 admin 全局口径
- store.WithoutTenant(ctx):显式跨租户旁路,插件即使 ctx 带租户也不过滤。
修复增量2 引入的回归:admin SystemCounts 数 KB 时被 admin 自己租户误过滤。
AdminOverview 改用旁路 ctx → 任务/KB/Doc/Eval 恢复全平台口径。
- Task 加 TenantID(插件自动填) + Owner(提交者 user.id) + isTenantScoped()。
SaveTask 记录 owner;RecentTasks/RecentRuns 按 owner+租户过滤"我的运行"。
RecentRuns 是 raw Table 查询绕过插件,手动补 owner+tenant WHERE。
live 验证:A 提交任务 → 行 owner/tenant 自动填对 ✓;A 的 /runs 只见己方、
B 空、legacy 无 owner 行被排除 ✓;admin/overview tasks_total=39/kb_count=21
= DB 全局真值(旁路生效,回归已修)✓。
Eval/Doc/DocLink 的 tenant 传播见 2b-B。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
2026-07-07 09:18:15 +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
|
9e43d07428
|
feat(gateway): 护栏拦截事件落库 + 安全事件流(T4.B)
- store.GuardrailEvent 表(sundynix_guardrail_event) + AppendGuardrailEvent/ListGuardrailEvents
- middleware.Guardrail(db):命中 blocked/suspect 时 best-effort 落库
(actor/kind/reason/signals/method/path/ip,独立超时 ctx)
- GET /api/v1/admin/guardrail-events:安全事件流(倒序,翻页)
- store.clampPage 抽出分页归一(audit/guardrail 共用)
- live:注入 "ignore all previous instructions" → 422 硬拦 + 事件留痕(kind=blocked)
- DEPTH_ROADMAP T4.B 护栏事件打勾
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
2026-07-02 09:31:31 +08:00 |
|
Blizzard
|
16c67dcb4f
|
feat(gateway): 敏感操作审计日志(T4.B)
- store.AuditLog 表(sundynix_audit_log) + AppendAudit/ListAudit
- middleware.Audit(db):只审计变更类(POST/PUT/DELETE/PATCH),收尾 best-effort
落库(独立超时 ctx,失败静默不拖垮主流程);挂管理组 + prompt 激活/撤销 + HITL 审批
- GET /api/v1/admin/audit:倒序审计流(limit/offset 翻页)
- live:PUT pricing / POST prompts/deactivate 留痕(actor/path/status/ip),GET 不记
- DEPTH_ROADMAP T4.B:overview✅ + audit✅ 打勾
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
2026-07-02 09:19:52 +08:00 |
|
Blizzard
|
e2104efc64
|
feat(gateway): admin/overview 系统级聚合接口 + Tier4 后端路线图
- GET /api/v1/admin/overview (RequireAdmin):全平台口径聚合——
用户/KB/文档总数 + 全局任务(今日/累计/趋势/终态) + 全局评测均分
+ 模型配置态(主/备/各kind数) + 提示词覆盖态 + 服务健康
- store.SystemCounts:全局 users/kb/doc 计数(区别 owner 隔离的个人口径)
- 区别桌面端个人 stats/overview:管理端概览改吃此接口(系统控制塔)
- DEPTH_ROADMAP 新增 Tier4 后端做实(A–F 六组,三路 Explore 审计产出)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
2026-07-02 08:59:28 +08:00 |
|
Blizzard
|
ecf4a80466
|
feat(llm): T2.1 模型路由 + Fallback —— 单 provider 抖动不再整体宕
现状:单 provider,一家 API 抖动/挂掉全平台不可用。加主备 failover:主模型调用失败
自动按序切备用,compose/ReAct/Chat 全路径透明白嫖。
- llm/failover.go: failoverModel 把多个 ToolCallingChatModel 串成主备链,按序调用、
遇错切下一个;它本身是 model.ToolCallingChatModel 故全路径透明。调用方主动取消
(ctx.Err()!=nil) 不切;模型自身请求超时走内部 ctx、不污染父 ctx 故仍 failover。
局限(v1):Stream 仅建流同步报错时切(已回流 token 的中途失败不切)。
- llm/pool.go: SetConfig 用激活配置(含 Fallbacks)重建——主+可用备用串成 failover 链,
无备用则直接用主;备用单个构建失败跳过不影响主链。
- contract.ModelConfig: 加 Fallbacks 字段(骑在主配置里下发,不改任何 bus/ServeConfig 签名)。
- gateway store.ActiveConfig: chat 把"其它已登记 chat 模型"按序填进 Fallbacks;
provide(main) + broadcast(admin) 共用 → 注册多个 chat 模型即自动成主备。
- bus.decryptConfig: 备用模型的 api_key(密文)一并解密。
测试:failover 单测(主可用不调备/主挂切备/全挂报错/取消不切/Stream 切备/WithTools 链)。
live 验证:active=死 ollama 主 + deepseek 备 → 任务连主拒连→自动切 deepseek→4s 完成。
DEPTH_ROADMAP T2.1(admin 注册多模型即主备,无需新 UI)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
2026-06-30 09:26:18 +08:00 |
|
Blizzard
|
46ef3df221
|
feat(security): LLM api_key 端到端加密(AES-256-GCM,磁盘+线缆均密文)
新增 sundynix-shared/secrets:AES-256-GCM,密钥由 SUNDYNIX_SECRET_KEY 经
SHA-256 派生;密文带 enc:1: 版本前缀,历史明文行自动透传(下次保存升级为密文)。
- 网关 SaveModel 加密落库;ListModels/TestModel 解密后脱敏/探测;
空或脱敏占位的 api_key 视为「未改」→ 沿用库内既有密文(不二次加密)。
- 密文经 NATS 原样下发;消费方解密集中在 bus 层 decryptConfig
(RequestConfig + SubscribeConfigUpdated)→ dispatcher/mcp-go 零改动。
- secrets.MustHaveKeyInProd():生产未设 SUNDYNIX_SECRET_KEY 直接 fatal,
gateway/dispatcher/mcp-go 启动各调一次(三服务须配相同密钥)。
- 修复 store.SaveModel 整行 Save 把 active 清零的旧 bug:改 Select(...).Updates
只覆盖可编辑列,改 key 不再顺手取消模型激活。
- secrets 单测:往返/空串/随机 nonce/错密钥 fail-closed/历史明文透传。
- production_readiness.md 2.1 更新为「已落地」。
验证:DB 列由明文 sk-…(35) → 密文 enc:1:…(90);dispatcher 从密文广播解密后
model config set;真实任务 √256→16、12×12→144 打通 DeepSeek(非降级桩)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-06-24 10:36:34 +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 |
|
Blizzard
|
4fd44380aa
|
refactor(store): DB 规约统一 —— 雪花字符串 id + created/updated/deleted_at 软删
所有数据库映射结构体收敛到统一基类,清理混乱。
- store/base.go:BaseModel{ID string(雪花,bwmarrin/snowflake) PK, CreatedAt, UpdatedAt,
DeletedAt gorm软删index} + BeforeCreate 生成 id + NewID()。
- 全模型嵌入 BaseModel:User/Task/LLMModel/KB/Doc/Agent(去掉各自 ID uint/CreatedAt);
Task 业务 id(task_xxx)挪到 TaskID 唯一列,主键统一雪花。
- 模型 id uint→string:admin :id 路由、SetActiveModel/DeleteModel/SaveModel、modelBody.ID。
- 一次性迁移 migrateLegacyIntIDs:检测旧整型 id(AutoMigrate 不改主键类型)→ 备份
sundynix_model 行(唯一不可再生的 API 密钥)→ 删旧表 → 按新规约重建 → 回灌模型(新雪花 id)。
其它表(User/Task/KB/Doc/Agent)为可重建测试数据,重置。
- Doc 预埋 Size/Preview/ObjectKey 字段,DocLink 表(为后续 B/C)。
验证:重启 gateway → 日志"回灌 2 条模型配置";PG sundynix_model.id=varchar、有
created_at/updated_at/deleted_at;DeepSeek/百炼 密钥保留(keylen 35);admin 列表返回
雪花 string id + 脱敏 key;健康五灯全绿。gateway build 通过。
注:mcp-go 的 sundynix_user_profile(Profile) 模型尚未套同规约,待跟进对齐。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
2026-06-13 16:45:52 +08:00 |
|
Blizzard
|
3b54e59ecf
|
feat: embedding 配置搬上控制面 — 数据源页可视化配置 + 热更新
embedding 从 env 改为控制面驱动(持久化+可视化),复用 chat 模型同套范式:
配置控制面泛化为按 kind(chat/embedding),加 embedding kind。
- shared: 配置 subjects 泛化 sundynix.config.<kind>.get/.updated;bus 方法改 kind 参数
(RequestConfig/ServeConfig/PublishConfigUpdated/SubscribeConfigUpdated)
- gateway: sundynix_model 加 kind 列(每 kind 唯一激活)+旧行回填 chat;admin 按 kind
增删改/激活/列表,测试连接 embedding 走 POST /embeddings;main 按 kind ServeConfig;
变更广播各 kind
- dispatcher: 取 chat 配置(kind 化)
- mcp-go: rag.Engine.SetEmbedding 热更新(RWMutex);main 取/订阅 embedding 控制面配置
(覆盖 env)
- admin 控制台: api 按 kind;抽出复用 ModelManager;ModelsPage(chat)+新 DatasourcesPage
(embedding + 向量/图库占位);routes 数据源页就绪
- 验证: 全模块 build✓ + e2e PASS + 控制台 npm build✓;live 全跑通——chat(DeepSeek 回填
kind 仍工作);mcp-go 不带 EMBED env 启动→控制台配 embedding(百炼)→测试连接✓→激活
→NATS 热更新 mcp-go→入库+语义检索'存向量的数据库'→Milvus;浏览器数据源页拉到激活配置
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
2026-06-10 17:25:54 +08:00 |
|
Blizzard
|
3c65189f30
|
feat: 配置控制面 + LLM Pool 接第三方在线 API (OpenAI 兼容)
后端从占位回显变为真实生成:管理员经控制面登记/激活模型,Gateway 经 NATS
下发,Dispatcher 热更新 LLM Pool,Eino 图用 OpenAI 兼容流式真实推理。
- shared: contract.ModelConfig(provider/base_url/api_key/model) + 配置 subjects;
bus.RequestModelConfig/ServeModelConfig/Publish/Subscribe ModelConfigUpdated
- gateway: store.LLMModel→sundynix_model(AutoMigrate,唯一激活) + admin REST
(GET/POST/active/delete/test models, api_key 脱敏) + main ServeModelConfig +
变更广播; 路由 /api/v1/admin/models*
- dispatcher: llm.Pool OpenAI 兼容 SSE 流式客户端(ChatStream) + 热更新配置 +
未配置则降级桩; poolModel.Ready()?真实流式:注入记忆的桩; main 取配置+订阅
- 开发期接在线 API 不拉本地模型(见 llm-provider-strategy memory)
- 验证: 4 模块 build✓ + e2e PASS; mock OpenAI 服务 live 跑通——登记/测试连接✓/
激活→NATS 热更新→提交→真实 SSE 流出 mock 回复, mock 日志证明端点被调用且
注入画像(老王)进了模型上下文
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
2026-06-10 15:41:39 +08:00 |
|