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.
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.
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.
- 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.
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.
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.
Define image model defaults with separate text and image cache prices while preserving explicit administrator overrides. Extend expression validation vectors and pricing regression coverage.
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.
Preserve optional image, text, and audio cache counts through canonical usage snapshots and merges. Keep explicit zero values and detach mutable token details.
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.
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.
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.htmlhttps://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
- 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
`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.
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
* 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]>