Commit Graph
6351 Commits
Author SHA1 Message Date
CaIon 385d2dfd10 feat(auth): add safe multi-RP ID passkey support
Preserve legacy credentials across primary RP ID changes and bind successful
assertions to their verified RP ID. Share domain selection across sign-in,
login verification and sensitive operations without replaying ceremonies.

Save domain settings atomically, preview known and unknown credential impact,
and require fresh confirmation before removing domains still in use. Recheck
trusted RP IDs when persisting credentials and record safe operation audits.

Use read-only configuration snapshots, accept trusted HTTPS intranet hosts,
check registration origins early, and preserve historical capitalization.
Update settings guidance and all supported translations.

Validation: SQLite 3.50.4, MySQL 8.0.46 and PostgreSQL 16.15, including fresh
and released-schema upgrade checks; Go regression and race checks; 79 frontend
tests; TypeScript, lint, frontend build and root Go build.

Security references: OWASP ASVS 5.0.0 V6.3.4 and V6.3.8, Authentication and
Session Management Cheat Sheets, and the WebAuthn RP ID/origin rules.
2026-09-11 23:15:29 +08:00
CaIon 74629e29f8 feat(plugins): enhance task streaming and model pricing 2026-09-11 21:44:56 +08:00
CaIon 251b76d863 feat(web): add administrator update reminders 2026-09-11 21:44:56 +08:00
CaIon ab489ab884 feat(channels): add plugin extensions to provider and model selection
Expose supported channel types in plugin options and let channel editors select extension models using the existing channel connection settings.

Add a gateway category, refine provider ordering and presentation, and prefer available plugins for legacy task providers during channel creation. Include the related translations and regression tests.

Validation in an isolated snapshot: 123 channel frontend tests, the plugin-options controller regression, TypeScript checks, affected-file lint, protected-header formatting, and the production frontend build passed.
2026-09-11 21:44:55 +08:00
CaIon d4c26bfb8d fix(channels): allow editing multi-key selection strategy
Preserve existing keys when updating random or polling selection, and omit the strategy for single-key channels. Validated with 46 configuration tests, type checks, lint, and formatting checks.
2026-09-11 21:44:55 +08:00
CaIon 505805a4c3 feat(web): unify channel setup and refine model and settings editors
- Share provider selection and tabbed configuration across channel creation and editing.
- Add provider descriptions, custom categories, inline model discovery, and model configuration tools.
- Improve batch model input, model mapping labels, parameter overrides, and required field indicators.
- Preserve existing Passkey domains and confirm domain changes.
- Include translations and regression coverage for the updated workflows.

Validation: 113 frontend tests, TypeScript checks, affected-file lint, production build, and protected-header formatting checks passed.
2026-09-11 21:44:55 +08:00
CaIon b3e279464c feat(web): review legacy pricing conversion before applying drafts
Add reviewed legacy-to-expression draft conversion with effective prices and provider billing adjustments. Standardize preview response handling and preserve explicit zero values, currency conversion, and save conflict detection. Reuse ConfirmDialog, CopyButton, and existing pricing preview components.
2026-09-11 21:44:54 +08:00
CaIon 39294418af feat(web): extend expression pricing editors and usage details
Support image cache and image count pricing across parsing, simulation, editing, summaries, and usage logs. Preserve task rule precedence, require confirmation before replacing expressions, and present ordered visual pricing rules. Include translations shared with the conversion flow.

Reuse ConfirmDialog and existing pricing controls. Expression, pricing, usage log, and editor regression suites pass; affected frontend files pass lint.
2026-09-11 21:44:54 +08:00
CaIon 25ec832faa feat(pricing): convert legacy prices into expression drafts
Add read-only conversion and preview APIs using shared effective price resolution, provider metadata, and legacy DALL-E multipliers. Standardize preview payloads under data.effective with billing metadata.

Validated conversion paths on real SQLite 3.50.4, MySQL 8.0.46, and PostgreSQL 16.15 instances.
2026-09-11 21:44:54 +08:00
CaIon f256e40bcb feat(billing): add expression defaults for GPT image models
Define image model defaults with separate text and image cache prices while preserving explicit administrator overrides. Extend expression validation vectors and pricing regression coverage.
2026-09-11 21:44:54 +08:00
CaIon f064bffa2b fix(billing): validate image quantities before reserving quota
Unify image count validation, outbound parameters, reservation, retries, and settlement. Reject explicit zero Ali parameters.n and insufficient supplemental reservations. Centralize image model classification, extract deprecated DALL-E compatibility, and record image cache billing inputs through shared audit injection.
2026-09-11 21:44:53 +08:00
CaIon f362c7c51b feat(billingexpr): support image cache and quantity variables
Add img_cr and bounded image_count inputs, expose settled billing inputs, and reuse expression digests. Extend the shared frontend contract fixtures and billing documentation.
2026-09-11 21:44:53 +08:00
CaIon 3cea2bf799 feat(relaykit): preserve cached input token breakdowns
Preserve optional image, text, and audio cache counts through canonical usage snapshots and merges. Keep explicit zero values and detach mutable token details.
2026-09-11 21:44:53 +08:00
CaIon 3e1b8b1532 feat(plugins): display localized changelogs with English fallback 2026-09-11 21:44:53 +08:00
CaIon b6566f33d9 feat: clarify passkey website configuration 2026-09-11 21:44:52 +08:00
Seefs bdef117505 fix: restore add split button in advanced custom routes (#7289) 2026-09-09 19:20:56 +08:00
CaIon 064ed943e1 feat(billing): support fixed per-request expression pricing
Add tier(name, fixed(usd)) pricing leaves to conditional token expressions,
with static validation, token/request billing metadata, and safe settlement
when successful requests have missing or zero token usage. Preserve group
and request multipliers, separate tool charges, and explicit zero prices.
Reject fixed expressions on unsupported Realtime and task-usage entrances.

Expose per-token and per-call tier editing, preserve both drafts, and show
request units consistently in pricing summaries and consume logs. Retain
matched-branch metadata and update all seven frontend locales.

Validation passed:
- go test ./pkg/billingexpr ./relay/helper ./service ./setting/billing_setting ./relay -count=1
- Frontend pricing, model-pricing, editor and usage-log regression suites
- Typecheck, scoped lint, protected-header formatting, i18n validation and build
- go test ./service -run TestFixedPriceBillingDatabaseMatrix -count=1 -v
  with TEST_FIXED_MYSQL_DSN and TEST_FIXED_POSTGRES_DSN set to isolated local
  test databases: SQLite 3.50.4, MySQL 8.0.46, PostgreSQL 16.15.
  All 39 database cases passed, including reserve/settle/refund, zero price,
  missing usage, branch changes and insufficient-quota handling.

No production database schema or migration changes.
2026-09-09 15:05:37 +08:00
CaIon 7cf9b473f6 fix(web): keep model pricing content in one scroll area
Move the current pricing summary and save errors into the editor scroll
container through its optional scrollHeader slot. Keep the save controls
available without nesting a separate capped scroll area above the editor.

Validation: model-pricing and related frontend regression tests, typecheck,
scoped lint, and protected-header formatting passed.
2026-09-09 15:05:37 +08:00
CaIon a20574136b fix(alibaba): correct Wan model protocols and usage accounting 2026-09-09 15:05:37 +08:00
CaIon 12be9975c0 fix(web): unify server error notifications
Preserve backend details and error causes, and report each failed operation
once across request, Query/Mutation, and page handling layers. Independent
operations with the same error message still receive separate notifications.

Migrate direct requests and query consumers, preserve inline and silent error
handling, and reject failed settings writes before success callbacks run.
Retain safe authentication messages, refresh behavior, and single-use proof
replay protection.

Validation: independently checked the staged snapshot with 117 frontend test
files (1105 tests), typecheck, scoped lint, and protected-header formatting.

Security references: OWASP ASVS 5.0.0, Authentication Cheat Sheet, and
Session Management Cheat Sheet:
https://owasp.org/www-project-application-security-verification-standard/
https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html
https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html
2026-09-09 15:05:36 +08:00
CaIon d52bdc0b40 feat(billing): add time-based pricing editor and expression previews 2026-09-09 15:04:15 +08:00
captainold 876903a8eb fix: 修正火山方舟渠道获取模型列表的端点路径 (#7203)
VolcEngine (type=45) 渠道 fetch models 时拼接 {base}/v1/models,
但火山方舟 OpenAI 兼容 API 根路径是 /api/v3,不存在 /v1/models,
导致「获取模型列表」固定返回 404。改为 {base}/api/v3/models。
2026-09-09 14:33:38 +08:00
OrrinandCaIon c79b74b683 fix(frontend): deduplicate /api/status requests (#7189)
* fix(frontend): deduplicate /api/status requests

* refactor(frontend): 明确守卫状态读取语义并补充去重回归测试

将 getFreshModuleAccess 重命名为 getModuleAccessForGuard。原名容易被
理解为强制获取最新状态,而该函数实际读取共享 ['status']  缓存,命中
过期条目时会立即返回旧值并在后台刷新,不阻塞导航。

新增 web/src/lib/__tests__/status-query.test.tsx,覆盖共享查询的三项
契约:多个消费者并发读取只产生一次 /api/status 请求;缓存命中时不再
请求;过期条目立即返回旧值并在后台刷新。三项断言均已通过反向改动
验证可捕获回归。

同时为本次改动涉及的函数补充 docstring,并为测试 helper 显式声明返
回类型。

* fix(frontend): refresh status before guards and subscribe binding dialog

Fixed  #7157
---------

Co-authored-by: CaIon <[email protected]>
2026-09-09 13:58:46 +08:00
CaIon 4fc9d1f1fa fix(options): rebuild options table primary key and stop pricing writes resetting rows
The options table on some long-lived deployments has no PRIMARY KEY on key, so mutateModelPricingOptions' ON CONFLICT DO NOTHING insert added duplicate default rows that overwrote real pricing on read and made model pricing updates appear to succeed without persisting across nodes.

- Read pricing rows under FOR UPDATE first and only insert defaults for keys that are missing; log when duplicate pricing keys are found.
- Add migrateOptionPrimaryKey: detect a missing unique key (including PostgreSQL constraint-backed keys), take a per-dialect lock, dedupe rows last-wins, rebuild into a temp table with the primary key, swap atomically, and keep the old rows in options_legacy_<ts>. Idempotent and non-blocking on failure.
- Run it in migrateDB before AutoMigrate on the master node.
2026-09-09 00:24:49 +08:00
CaIon 9bf328d974 fix: preserve provider fields in Sora video queries 2026-09-08 23:46:37 +08:00
CaIon ea7cb0ba4e refactor(web): unify table cells and quota details 2026-09-08 20:56:03 +08:00
CaIon ebe4c368f2 refactor: modernize Go code conventions 2026-09-08 20:55:03 +08:00
CaIon fff0635bb1 docs: update project architecture and Go conventions 2026-09-08 20:53:25 +08:00
CaIon 524455fac3 feat(redemptions): add batch deletion and optional file exports
Add confirmed multi-select deletion through one batch API request and one
soft-delete statement. Record the affected count and requested IDs in a
separate batch audit event, and identify legacy events with missing counts.

After creation, offer an unchecked Save as a file option with TXT/Markdown
formats and optional name/quota fields. Keep Done as the default completion
action. Include translations for all seven frontend locales.

Validation:
- Redemption and audit frontend regression tests, typecheck, and scoped lint.
- go build ./...
- go test ./controller -run '^TestDeleteRedemptionBatch$' -count=1 -v
  with TEST_MYSQL_DSN, TEST_MYSQL_LOG_DSN, TEST_POSTGRES_DSN,
  and TEST_POSTGRES_LOG_DSN set to isolated primary and log databases.
- Real SQLite 3.50.4, MySQL 8.4.11, and PostgreSQL 16.15 passed, including
  deletion of 15 records, duplicate/missing IDs, zero-row retries, audit
  deduplication, invalid input, and exclusion of credentials from logs.
2026-09-08 20:47:01 +08:00
CaIon 950644c9d5 fix(keys): preserve spacing after desktop quota content
Bound desktop quota content to 180px so column width provides whitespace before the group column. Remove the quota-only padding override to use the same cell padding as other columns. Preserve the mobile quota layout.

Validation: layout regressions failed before the fix and all 26 API key listing tests passed afterward. TypeScript, scoped lint, formatting, production build, and git diff checks passed.
2026-09-08 19:59:27 +08:00
CaIon bd22e45a74 style(keys): widen the desktop quota column
Increase the quota column width and minimum width from 220px to 260px to give the side-by-side amounts more room.

Validation: all 26 API key listing tests, TypeScript, scoped lint, formatting, and git diff checks passed.
2026-09-08 19:56:41 +08:00
CaIon 551bb63edf fix(keys): show desktop quota amounts side by side
Place remaining quota on the left and used quota on the right above the progress bar, without visible labels in desktop rows. Preserve accessible descriptions and the existing mobile labels and stacked layout.

Validation: updated regressions failed before the change and all 26 API key listing tests passed afterward. TypeScript, scoped lint, formatting, production build, and git diff checks passed.
2026-09-08 19:55:28 +08:00
CaIon 8f72ecbbfd feat(usage-logs): add searchable group filter
Reuse the shared Combobox to suggest groups for the active log view while allowing historical group names to be entered manually. Exclude the automatic routing pseudo-group from suggestions and preserve masking, reset, URL navigation, and mobile drawer behavior.

Extend the existing Combobox with keyboard event forwarding and accessible labels, preserve the selected custom value on focus, and close suggestions on blur. Enter confirms a selection before submitting the filter.

Validation: 25 tests passed across the shared Combobox and log group, type, and mobile filter suites. TypeScript, scoped lint, formatting, and git diff checks passed.
2026-09-08 19:51:33 +08:00
CaIon 2bec370629 feat(web): refine API key and user quota displays
Show remaining and used API key quota with a progress bar, and use consistent mobile cards, group multiplier badges, and activity timestamps. Present available user balance with used quota underneath and translate the new labels.

Resolve full API keys only for explicit copy or chat actions. Reviewed OWASP Authentication and Session Management guidance and ASVS 5.0.0 V14.2.6 and V8.3.1; backend authorization is unchanged, and regression tests cover refused and denied key resolution. This frontend change does not assert application-wide ASVS compliance.

Validation: 55 related component tests passed; the latest mobile group and quota changes passed 35 focused tests. TypeScript, scoped lint, formatting, production build, and git diff checks passed. Responsive previews verified narrow screens and finite, unlimited, exhausted, and inactive quota states.
2026-09-08 19:49:55 +08:00
CaIon a5e41a8933 feat(usage-logs): refine mobile layout and keep quick actions visible 2026-09-08 17:31:19 +08:00
CaIon 71c1fd7caa feat(models): improve model listing, pricing and visibility filters
Include configured channel models without creating metadata, derive square
visibility from live routes and metadata policy, and filter before pagination.

Share pricing display with the model square, show expression tiers and task
unit prices, preserve zero rates, and expose full pricing and visibility
reasons from compact responsive rows. Complete all seven locale translations.

Validated frontend tests, typecheck, lint and production build, plus the
model database matrix on SQLite 3.50.4, MySQL 5.7.44 and PostgreSQL 9.6.24.
2026-09-08 17:03:10 +08:00
CaIon 0e0ba152bd feat(pricing): improve pricing editors and log display 2026-09-08 15:15:56 +08:00
CaIon eb76b136b8 feat(channels): improve plugin channel setup and icons 2026-09-08 15:15:55 +08:00
CaIon 9843309200 feat(web): improve plugin management and marketplace 2026-09-08 15:15:55 +08:00
CaIon 99974a814f feat(plugins): extend plugin metadata and icon support 2026-09-08 15:15:55 +08:00
CaIon 75e5332094 feat(pricing): support site currency in pricing editors 2026-09-08 12:12:46 +08:00
CaIon bee45b58a3 fix(web): switch the pricing card grid to three columns at xl
The model card grid and its loading skeleton only reached three columns at
2xl, leaving a two-column layout on common desktop widths. Use the xl
breakpoint for both and lock it with a test.
2026-09-07 22:40:11 +08:00
CaIon 210734bb73 refactor(task): remove the custom-plugin layer switch
TaskPluginOverrideEnabled had no UI since the master switch landed, yet
when left off it marked every third-party plugin "disabled; platform
unavailable" regardless of its own toggle. Drop the option, env var,
registry flag, and the dead branch in ListTaskPlugins; the master switch
and per-plugin toggles are the only two levels now.
2026-09-07 22:38:09 +08:00
CaIon 92bc7ff73c fix(plugins): make sunoapi alias-safe and lock alias echo across built-ins
Decode on ctx.upstreamModel || ctx.model and echo ctx.model; fix the
lyrics/music render branch that read a nonexistent ctx.requestBody.model;
stop sending empty Accept/Content-Type. Bump sunoapi to 1.0.2. Add an
alias-echo table test covering every built-in.
2026-09-07 22:38:08 +08:00
CaIon 6298b0f323 fix(plugin): suppress factory layer when disabling an overridden task plugin
Disabling a task plugin that has both a factory built-in and an override
row only flipped the override flag, so the built-in kept routing the same
models and same-name uploads (e.g. minimax-h3 vs MiniMax-H3) still hit a
routing conflict. Now the key also enters the disabled-factory set and the
list reports "disabled" instead of "disabled_fallback" when nothing serves.
2026-09-07 18:18:55 +08:00
CaIon 5c7cca0155 fix(perf): return hourly success-rate series for model health bar
The perf summary API only returned the last three non-empty buckets as
bare success rates, so the 24-slot status strip on model cards never lit
more than three bars and could not show hours without traffic.

Replace recent_success_rates with recent_success_series: one timestamped
point per hour that had requests, aligned to hour start regardless of
the configured bucket size. The badge now anchors its 24 slots to the
client's current hour and places each point by timestamp, leaving hours
without data gray.
2026-09-07 16:24:31 +08:00
CaIon 387a409148 fix(web): keep drawer popups interactive and shim storage in tests
- Portal Combobox and Select popups into the vaul DrawerContent via a
  portal-container context so they stay inside the Radix modal layer
  instead of inheriting body pointer-events: none
- Provide an in-memory localStorage/sessionStorage in test-setup when the
  Node 25+ global accessor resolves to undefined and shadows jsdom
- Add regression tests for popups rendered inside and outside the drawer
2026-09-07 15:02:17 +08:00
CaIon 7bbe85bcb0 refactor(json): route JSON helpers through a host-injectable codec
`common/json.go` and `relaykit/relayconvert/kitutil/json.go` were two
hard-wired copies of the same encoding/json wrapper, so swapping the JSON
engine required editing both modules.

- kitutil defines a `Codec` interface with a standard-library default and
  a `SetCodec` hook, mirroring the existing SetLogging host hook; every
  kitutil JSON helper and relaykit DTO (un)marshal method goes through it
- `common/json.go` forwards to kitutil and injects `hostJSONCodec` from
  init() so tests run on the same engine as production; swapping the
  engine now touches only this type in the root module
- route the remaining direct encoding/json calls inside relaykit
  (dto/values.go, responses stream validation) through kitutil
- add a codec routing test and a host codec conformance test locking the
  encoding semantics the DTOs depend on

Direct encoding/json call sites in the root module are left for a
separate cleanup.
2026-09-07 13:16:44 +08:00
CaIon 6e10f9bc92 fix(relay): preserve Kimi K3 dynamic tool loading messages
Kimi K3 injects tools mid-conversation via a system message that carries
a `tools` array. `dto.Message` had no such field, so the tools were
silently dropped during the parse/re-marshal round trip and the upstream
rejected the request with `'tool_choice'='required' requires a 'tools'
field`.

- add `Message.Tools` (json.RawMessage passthrough)
- omit the `content` key only for tool-loading messages with nil content,
  as Kimi rejects `tools` next to `content`; all other messages keep
  emitting `"content": null`
- count message-level tools in token estimation
- skip tool-loading messages in channel system prompt injection and make
  the compatible handler reuse applySystemPromptIfNeeded
- add kimi-k3 to the moonshot model list

Fixes #7235
2026-09-07 13:16:44 +08:00
Calcium-Ionandqiuliw 3b4652269a feat(ali): support wan3.0 all-in-one video models
* feat(ali): support wan3.0 all-in-one video models

Extend the Alibaba task plugin for wan3.0-video / wan3.0-video-prime
using DashScope media, resolution/ratio, duration rules, and billing ratios.

* fix(ali): make wan3.0 smart duration billable and alias-safe

Review fixes on top of #7240 (qiuliw):

- duration -1 never reached the plugin: the host rejects negative
  canonical duration/seconds facts before any hook runs, on every
  entry point. Decoders now normalize -1 into an auto_duration marker;
  convert emits -1 upstream and bills 30s up front; non-wan3.0 models
  reject the marker instead of silently defaulting to 5s.
- extractUsageOnComplete read output.duration/output.resolution, but
  wan3.0 reports usage.output_video_duration and numeric usage.SR, so
  smart-duration and resolution settlement never reconciled. Read the
  usage block first, keep the legacy output fields as fallback.
- convert keyed default resolution on the client model name, so a
  channel-mapped alias fell to 720P while the direct request got 1080P.
  Every model-shaped decision in convert now uses ctx.upstreamModel.
- Unknown wan3.0 size values were silently coerced to 1080P; reject them.
- Image-only openai_responses input was accepted for every model,
  regressing t2v models into pre-consume then upstream rejection.
  Restore the guard and allow image-only for i2v and wan3.0 only.
- Native passthrough dropped wan3.0 parameters (ratio, audio) unless
  media was present; forward them via metadata for wan3.0.
- Hoist the triplicated size-to-resolution map; add wan3.0 contract tests.

---------

Co-authored-by: qiuliw <[email protected]>
2026-09-07 12:37:43 +08:00