Commit Graph
6471 Commits
Author SHA1 Message Date
jimmyleocn dfd3cd8930 fix(web): hide system settings from non-root admins (#7513) 2026-09-30 22:32:30 +08:00
Schwa[R]z 8112120673 fix(web): Add class to wrap the long strings at auto-disable status tooltip content in channel manage page (#7604) 2026-09-30 21:50:28 +08:00
feitianbubu d0cb7347c0 fix: use max_completion_tokens for gpt-6-sol and gpt-6-luna (#7559) 2026-09-30 21:50:05 +08:00
Seefs feefe09f27 fix: isolate TLS configs across HTTP transports (#7627) 2026-09-30 21:49:33 +08:00
CaIon 2035a82aeb feat(web): add a refresh button to the channels table
A Refresh button next to the sensitive-data toggle reloads the channel
list with the current search, filters, sorting and page. It is marked
busy and its icon spins while the list is loading.
2026-09-30 20:52:57 +08:00
CaIon ae73ef8e25 feat(plugins): add Seedream 5.0 flash and price each Seedream model by its own tiers
The doubao plugin now serves doubao-seedream-5-0-flash-260915 with 1K,
1.5K and 2K sizes, layer decomposition, output_format and the same
background rules as 5.0 pro.

Seedream models shared one usage schema, so the pricing matrix offered
an up-to-1.5K price and a layer decomposition price for every model.
Each model now gets a profile from its capability table: Seedream 5.0,
5.0 lite and 4.5 start at 2K and show a single image price, and layer
decomposition is listed only for 5.0 pro and flash. Seedance profiles
are built by the same helper. On completion a single-tier model counts
every delivered image at the upper tier, even when the result has no
parseable size.

Usage facts keep all four released image keys, and every Seedance model
still reports video_input, so expressions saved before the per-model
profiles charge as before.
2026-09-30 20:52:51 +08:00
CaIon 4924361aef feat(auth): edit the name and permissions of an access token
The token menu now opens an edit dialog instead of a rename prompt.
Renaming still needs no verification. Changing the permissions requires
step-up verification bound to the token id and the new grant, so a
proof cannot be replayed for another token or another set of
permissions; the grant is checked against what the owner can do, the
same as at creation. PATCH /api/user/access_tokens/:id takes an
optional scopes list and is rate limited like the other token routes.

A token that holds permissions the catalog no longer offers can still
be renamed and keeps them; a new grant only contains offered
permissions. Edit stays disabled until the permission catalog has
loaded.

Grant changes are audited as access_token.update with the previous and
new scopes, and audit details show both as permission names.

The permission picker for tokens and admin users now uses toggle
buttons. Token permissions are grouped by personal, administration and
system, each group collapsible with a selected count and select-all or
clear.
2026-09-30 20:52:36 +08:00
CaIon 2506e1b980 fix(auth): reject non-standard roles when creating a user
CreateUser accepted any integer role below the operator's own, so an
admin could create a user with role 5 or -1, and a root user's request
for role 99 went on to step-up verification before failing. Only the
guest, common, admin and root roles are accepted now; any other value
fails with an invalid-parameter error before verification and nothing
is written.
2026-09-30 20:52:10 +08:00
CaIon c71eefbcd1 docs: update readme 2026-09-30 17:24:20 +08:00
CaIon 2ffc595901 feat(jsplugin): run task plugins on moejs
Task plugins now run on github.com/Calcium-Ion/moejs v0.1.0-alpha.3
instead of Sobek, and the host utils are ported to it. The plugin API is
unchanged. Code compiled from strings is no longer allowed: eval and the
Function constructors throw an EvalError.

Hooks receive host values without defensive copies. The engine converts
an object or array when the hook first reads it and never writes
JavaScript changes back to the host value. Stored protocol state and task
views are passed as raw JSON and parsed inside the runtime instead of
being decoded into Go maps first. An idle runtime drops its references to
the last call's arguments.

Whether an optional hook is exported is decided once when the plugin
loads, so checking for it no longer takes an execution slot.

Usage validation returns the normalized facts in a new map instead of
writing into the hook result, so a hook that returns the request body no
longer changes it. The request descriptor is copied instead of being
round-tripped through JSON.
2026-09-30 17:24:19 +08:00
CaIon 335ebcff71 fix(relayconvert): keep Responses custom tools on Chat Completions upstreams
Responses to Chat conversion kept only function tools, so Codex custom
tools such as exec and apply_patch were dropped while the request still
succeeded. The model then called the remaining tools with made-up
arguments and Codex failed with "exec cell noop not found".

Custom tools are now sent as Chat functions that take a single string
input, with the grammar kept in the description. A forced custom
tool_choice becomes the matching function choice, and custom_tool_call
history items round-trip as function calls and tool messages.

On the way back, function calls to those tools are restored as
custom_tool_call output items, and streams emit the
custom_tool_call_input delta and done events.
2026-09-30 17:24:19 +08:00
CaIon caca52f8de feat(auth): replace the dashboard access token with scoped access tokens
Each user can now hold up to 20 named access tokens in the
user_access_tokens table instead of a single token on the user row.
Tokens are shown once at creation (nap_ prefix) and stored as a SHA-256
digest. They expire after 30 days by default; a token without expiry is
allowed with a warning.

A token only reaches the routes its scopes allow. Scopes are picked from
the same permission matrix as admin permissions and are limited to what
the owner can do; every management route declares the scope it needs,
and routes without a declaration reject tokens. Token management itself
always requires a browser session.

Tokens can complete step-up verification, so verified actions such as
changing a password or 2FA settings work with a token; such changes sign
out all browser sessions. Disabling a user keeps their tokens, deleting
the account removes them.

The existing dashboard token keeps working for 30 days after the
upgrade. It can be revoked but no longer regenerated, and afterwards it
is rejected with ACCESS_TOKEN_LEGACY_RETIRED. The security page lists
tokens with their access records, and audit details show scope names.
2026-09-30 17:24:19 +08:00
CaIon 6cbb1c7edb feat(auth): require step-up verification for admin user management
Deleting a user, changing their status or role, setting a password or
admin permissions, creating an admin, resetting a passkey, disabling 2FA
and clearing a binding now need a single-use verification proof. The
proof context names the managed user (and the action or binding where
relevant), so it cannot be reused for another user or operation. Quota
adjustments and edits to display name, group or remark stay unchanged.

The admin.user.* scopes are issued only to admins. An admin with 2FA or
a passkey must use one of them; otherwise password or a bound OAuth
account is accepted. The users page asks for verification before sending
each gated request.
2026-09-30 17:24:19 +08:00
CaIon 3509ae7c19 fix(pricing): keep prices saved before a usage profile narrows editable
An unchanged model expression or provider override of a single-plugin
model stays saveable after the plugin drops a fact from its profile, so
a full pricing save is no longer blocked by existing prices. Shared
models still follow each provider's profile.

The task pricing table reads a dropped fact at the value a plugin keeps
reporting: price terms on dropped counts are omitted, tiers requiring a
dropped boolean to be true are skipped, and other conditions on dropped
facts are removed with the first matching tier kept. Existing prices
open in the table with only the remaining fields.
2026-09-30 17:24:19 +08:00
CaIon 87bb71e7fc feat(plugins): serve Seedream images through the OpenAI Images protocol in doubao
Claim openai_image for the Seedream image models so /v1/images/generations and
/v1/images/edits run through the task plugin instead of the HTTP image relay,
which has no usage facts for u() expressions.

Requests map onto the same Ark body as /doubao/api/v3/images/generations, so
validation and usage facts are identical: images_up_to_1_5k, images_above_1_5k,
input_images and layer_decomposition. n only accepts 1 (group generation covers
multiple images), stream and mask are rejected, response_format is left to the
host, and multipart uploads are inlined as data:image Base64 URLs.
2026-09-30 17:24:19 +08:00
CaIon f5e54ccdb2 fix(web): revalidate marketplace fetches so stale caches do not fail integrity checks
Marketplace hosts serve versioned plugin sources as immutable. When a file
is republished in place, a browser that cached the earlier bytes keeps
reading them, while the index is fetched fresh and declares the new hash,
so the install dialog reports a sha256 mismatch for a correct source.

Fetch the plugin source, the sidecar icon and the index with
cache: 'no-cache' so each request revalidates with the host (a 304 when
unchanged).
2026-09-30 17:24:18 +08:00
Seefs 789c970199 fix(claude): preserve auto mode safeguards in native requests (#7598) 2026-09-28 20:48:08 +08:00
Zane-0x5a c2b7a9a9e0 fix(claude): preserve per-message output_config in Claude messages (#7561) 2026-09-25 12:43:11 +08:00
zenor0 d04c118c88 fix(channel): preserve Responses WebSocket setting on save (#7468) 2026-09-23 21:00:00 +08:00
指短琴长 c76452d224 fix(playground): add break-all to playground input (#6600) 2026-09-23 17:06:35 +08:00
feitianbubu 6c14c0762d feat: highlight differing values in source price expressions (#7543) 2026-09-23 13:47:12 +08:00
feitianbubu a46f045d6d fix: match current price column width to source columns so expressions wrap alike (#7542) 2026-09-23 12:53:14 +08:00
musenlinc 5401874c63 fix(ci): align ldflags -X package path with module path so release binaries embed the real version (#7536)
The -X flag in release.yml and electron-build.yml used 'new-api/common.Version',
but the module path is github.com/QuantumNous/new-api, so the linker silently
dropped the injection and every bare-binary release asset reports v0.0.0
(GET /api/status, startup log). The Dockerfile already uses the correct
github.com/QuantumNous/new-api/common.Version path, which is why Docker
images are unaffected.

Fixes the intent of #2242 (closed as 'by design' before the -X injection
existed; the current flag is present but inert due to the path mismatch).
2026-09-23 12:07:17 +08:00
RedwindA 996adffe51 fix(web): keep text selection when opening a model pricing row for editing (#7403) 2026-09-22 16:40:59 +08:00
feitianbubu 8cb88ebd17 fix: move force operation into confirm slot so plugin-in-use dialog has one cancel button (#7528) 2026-09-22 16:37:08 +08:00
Yorick 9310231b3c fix(logs): keep model badge text readable and compact (#7504)
* fix(logs): prevent model badge descenders from clipping

* fix(logs): constrain wrapped model badge width

* fix(logs): preserve compact model name line spacing

* fix(logs): give wrapped model names sufficient line height
2026-09-22 00:07:07 +08:00
CaIonandByebyDoggy 0aec08fee8 chore: credit #7444 author for the Claude tool_result fix landed in #7512
Co-Authored-By: ByebyDoggy <[email protected]>
2026-09-21 23:02:57 +08:00
CaIon b6809a52df fix(web): resolve safe constants in plugin metadata previews 2026-09-21 23:02:37 +08:00
Calcium-IonandMOON-DREAM-STARS 4eb3b91605 fix(relayconvert): hoist Claude tool_result images and segment Responses reasoning items (#7512)
Claude Messages -> Chat: a tool_result whose content is a block array was
stringified into the Chat tool message, so image base64 travelled upstream
as text instead of vision input. Text blocks now stay on the tool message
(joined with newlines) and image blocks become image_url parts on the user
message the same Claude message produces, which lands after the tool batch
and keeps parallel tool messages contiguous. Image-only results carry an
"[image]" placeholder; arrays with other block types keep the stringified
form.

Chat stream -> Responses stream: reasoning items now emit
response.reasoning_summary_part.added and .done around the summary text,
and deltas that arrive after a mid-stream finish_reason open a new
reasoning or message item instead of appending to the closed one. Closed
items are snapshotted so the completed response lists every segment.

Closes #7407
Closes #7495

Co-Authored-By: MOON-DREAM-STARS <[email protected]>
2026-09-21 22:50:27 +08:00
Calcium-IonandMOON-DREAM-STARS 6e9de44a7d fix(relayconvert): hoist Responses tool-output media into a user message (#7510)
A function_call_output whose output is a Responses content-part array was
stringified into the Chat tool message, so image data URLs travelled
upstream as base64 text instead of vision input.

Text parts now stay on the tool message (joined with newlines) and media
parts are mapped like regular content parts, then emitted as one user
message once the contiguous tool batch ends so parallel tool outputs stay
adjacent to their assistant tool_calls message. Media-only outputs carry
an "[image]"-style placeholder because upstreams reject empty tool
content; payloads that are not content-part arrays keep the stringified
form.

Closes #7498

Co-Authored-By: MOON-DREAM-STARS <[email protected]>
2026-09-21 22:11:21 +08:00
CaIon 54eee488be fix(web): isolate theme preferences in local storage 2026-09-21 21:01:16 +08:00
CaIon d61d6be759 fix(task): accept any 2xx upstream status on task submission
The submit relay treated every status other than 200 as an upstream
failure, so a task API that answers 201 Created or 202 Accepted (for
example Tencent's wand-vega-video-1.0-lite) returned fail_to_fetch_task
and parseSubmitResponse never ran. The check predates the plugin system,
when every built-in adaptor answered 200; the plugin adaptor already
passes the exact statusCode to parseSubmitResponse and polling has
always classified 2xx as a successful response.

Accept any 2xx before parsing and keep failing other statuses with the
upstream status and body. Add a relay regression that drives a plugin
submission against a real upstream returning 200/201/202 and 400/502,
and document the submit-side 2xx contract in the plugin API.

Fixes #7478
2026-09-21 21:01:16 +08:00
CaIon 2c175190c4 perf(plugins): sync task plugins from hashes and load source only for changed rows
Every node polls the active override set every 30 seconds, and the
snapshot query selected whole rows, so each poll pulled every plugin's
full source and icon from the database only to compare source_hash and
discard them. With sources allowed up to 8 MiB that is real traffic.

Skip the source and icon columns in the sync snapshot and fetch source by
row id only for plugins whose hash changed. A row never changes source in
place, so the id from the snapshot identifies exactly the text its hash
describes. A failed source load is handled like a compile failure: the
running plugin stays and the next poll retries.
2026-09-21 21:01:16 +08:00
CaIon c0cff23a3a fix(plugins): store task plugin source as longtext on MySQL and raise the upload cap to 8 MiB
A bare TEXT column holds 64 KiB on MySQL, and the shipped alibaba plugin
is already 73 KB, so uploading an override of it failed with "Data too
long for column 'source'" or was silently truncated. The 1 MiB upload
cap also blocks the larger plugins planned next.

Add model.LongText, a string type that picks longtext on MySQL and text
on PostgreSQL and SQLite through GormDBDataType, and use it for source
and icon. Neither type carries a length, so AutoMigrate leaves an
up-to-date column alone and widens the shipped MySQL text column once
without data loss. Raise the source cap to 8 MiB on the backend and in
the frontend picker, importers and locale strings.

Verified fresh and rc.39-upgrade startups twice each on SQLite, MySQL
5.7.44 and 8.4.11, PostgreSQL 9.6.24 and 17.11; the second start issues
no DDL and a 73 KB source round-trips on every engine.
2026-09-21 21:01:16 +08:00
CaIon e537dc380b fix(web): expose plugin activation after upload 2026-09-21 21:01:15 +08:00
CaIon 00e8a00cb4 fix(web): include provider icons in Windows builds 2026-09-21 21:01:15 +08:00
feitianbubu 474ed66fb1 fix(plugins/alibaba): keep upstream metadata in openai_image render (#7507) 2026-09-21 20:46:28 +08:00
feitianbubu 9c293e8c02 test(billing): fix websocket rejection refund test after pre-consume dropped output estimation (#7491) 2026-09-21 12:48:24 +08:00
CaIon 9a0be8750a fix(web): keep task pricing editable after a plugin narrows its enum values
When a task plugin stops declaring an enum value (Seedance 2.0 mini now
offers 480p and 720p only), an expression saved with 1080p and 4k
branches no longer opened in the visual price table: the parser rejected
the whole tier chain on the first undeclared value, the editor fell back
to expression mode with a "cannot be represented" notice, and switching
to the visual editor reset every price to zero.

Treat a branch on an undeclared enum value as unreachable and skip it,
so the remaining tiers stay editable with their prices preserved. Nested
conditions in the pricing display treat such a comparison as never
matching. Editing a price regenerates the expression without the
unreachable branches; opening the editor alone leaves the stored
expression unchanged.
2026-09-20 23:27:57 +08:00
CaIon 47713bcb17 feat: update plugins 2026-09-20 23:23:48 +08:00
CaIon 9978ee1e25 feat(billing): configure trust threshold and input pre-consume multiplier 2026-09-20 22:17:20 +08:00
CaIon 65d3a2171f fix(plugins): price only the resolutions each Seedance and Wan model offers
The doubao plugin shared one usage schema across every Seedance model, so
the pricing matrix listed 1080p and 4k rows for Seedance 2.0 mini and fast
and a 4k row for Seedance 2.5, none of which Ark offers, and priced 1.0
and 1.5 pro by a reference-video dimension they do not accept. Describe
each video model with its resolutions, reference-video and audio
capabilities from the Ark model list and derive the usage schema,
examples and profiles from that table; reject unsupported resolutions at
submission, reserve the model's highest tier when the resolution is left
to Ark and ignore an out-of-profile resolution on completion. Seedance
1.5 pro gains the generate_audio fact its audio and silent prices need.

The alibaba plugin likewise derives one Wan video profile per resolution
set from the model capability table instead of listing 480P/720P/1080P
for every model, and adds the audio fact for wan2.6-i2v-flash.
2026-09-20 22:17:20 +08:00
feitianbubu 3abbb8198e feat: record perf metrics when async tasks reach terminal status (#7481) 2026-09-20 20:16:50 +08:00
CaIon 2fddb863f2 feat(models): add bulk field selection to metadata sync 2026-09-20 19:27:37 +08:00
CaIon a5bf940220 fix(web): correct dialog viewport fallbacks and editor gutter alignment 2026-09-20 18:24:39 +08:00
CaIon 03563a4a79 feat(plugins): serve OpenAI Images API through task plugins
Add the synchronous openai_image host protocol so a task plugin can claim
POST /v1/images/generations and /v1/images/edits; the host submits the
task, polls it inside the request and lets the plugin render the OpenAI
image response. Unclaimed models still fall back to the HTTP image relay.

- Migrate Ali (Bailian) image models to the alibaba plugin and remove the
  ali channel image/wan adaptors and the qwen model setting
- Add Doubao Seedream image generation to the doubao plugin
- Support retainResult on routes and indexed multipart file references
- Settle image counts from upstream usage or image payloads; document the
  rule in the billing conventions and plugin API docs
- Show billing source and task artifacts in usage logs; rename the
  DoubaoVideo channel display name to Doubao and refresh the favicon
2026-09-20 17:58:45 +08:00
CaIon c49972441e fix(web): keep mobile dialog actions within visible viewport 2026-09-20 17:51:53 +08:00
CaIon 585c4610e5 feat(keys): show and copy configured API addresses 2026-09-20 17:51:53 +08:00
CaIon d904b97000 feat(settings): improve group configuration UX and drag sorting 2026-09-20 17:51:53 +08:00
CaIon da2540dda1 fix(channels): align card metrics and remove badge spacing 2026-09-20 17:51:53 +08:00