1. 27 Jul, 2026 5 commits
    • refactor: extract protocol conversion layer into standalone relaykit module (#6369) · 86ac0f77
      * test(relayconvert): add golden snapshot matrix and relaykit boundary guard
      
      Phase 0 of the relaykit extraction plan: pin byte-level output of every
      registered (from,to) request/response/stream conversion route, and
      forbid kit-bound packages from growing host-only imports.
      
      * wip(relayconvert): drop gin.Context from converter signatures; add convmeta draft
      
      Phase 1 in progress: relayconvert now takes context.Context; host media
      resolver adapts gin.Context back at the service boundary.
      
      * refactor(relayconvert): decouple converters from RelayInfo, gin, and settings
      
      Phase 1 of the relaykit extraction plan:
      - converters now depend on convmeta.Meta (implemented by RelayInfo) instead
        of *relaycommon.RelayInfo; ClaudeConvertInfo and the format guesser move
        to convmeta with aliases left behind
      - host settings reach converters via a convmeta.Options snapshot built in
        RelayInfo.ConvOptions; no more model_setting/reasoning global reads inside
        the conversion layer
      - effort-suffix helpers move to service/relayconvert/reasoning (old package
        forwards); chat-to-responses upgrade policy moves to service (host routing
        logic, not conversion)
      - golden conversion matrix unchanged
      
      * test(relayconvert): tighten boundary — kit packages now free of gin/setting imports
      
      * refactor(dto): drop gin and logger dependencies
      
      Phase 2 (part 1): dto.Request.IsStream now takes *http.Request instead of
      *gin.Context (Gemini's impl reads query/path off the std request); dto's
      three logger calls become common.SysError. Boundary test allowlist is now
      empty — kit-bound packages import no gin/setting/logger/model.
      
      * refactor(kit): extract dependency-free kitutil; dto/types/relayconvert stop importing common
      
      Phase 2 of the relaykit extraction plan:
      - new service/relayconvert/kitutil holds the pure helpers the kit needs
        (JSON wrappers, pointer/string/uuid/timestamp utils, MaskSensitiveInfo,
        pluggable LogInfo/LogError hooks, Debug flag)
      - dto, types, and all relayconvert packages now use kitutil; their only
        remaining internal deps are dto/types/constant
      - common keeps every original symbol (MaskSensitiveInfo delegates to
        kitutil) so host code is untouched; main.go routes kit logging into
        common.SysLog/SysError and mirrors DebugEnabled
      - golden conversion matrix unchanged
      
      * refactor(kit): move EndpointType/FinishReason to types; OpenRouter dialect via Options
      
      Kit packages (dto/types/relayconvert/reasonmap) no longer import constant:
      - EndpointType and finish-reason values live in types; constant re-exports
      - the OpenRouter special-case in claude->openai request conversion reads
        Options.OpenRouterDialect, set by the host from the channel type;
        InitChannelMeta invalidates the cached snapshot on channel switch
      
      * refactor: extract relaykit submodule (dto/types/relayconvert/reasonmap)
      
      Phase 3 of the relaykit extraction plan:
      - new go module github.com/QuantumNous/new-api/relaykit containing dto
        (minus task family), types, relayconvert (with convmeta/kitutil/reasoning),
        and reasonmap; host consumes it via require + replace, go.work for dev
      - task-family dto (task/suno/midjourney/video) stays in the host dto
        package; dual-consumer host files alias it as taskdto
      - relaykit builds and tests standalone (GOWORK=off): no host imports,
        no gin, no DB, no settings
      - golden conversion matrix unchanged
      
      * build(docker): copy relaykit/go.mod before go mod download
      
      The local-replace submodule's go.mod must exist inside the build context
      for the main module graph to resolve.
      
      * fix: address relaykit extraction regressions
      
      * fix: address relaykit review regressions
      
      * docs: document Meta nil receiver contract
      
      * fix(relaykit): fail OpenAI→Claude conversion without max_tokens; reject negative default_max_tokens
      
      The Claude Messages API requires max_tokens (omitting it is a 400
      "Field required"), but with a nil Options.Claude.DefaultMaxTokens hook
      the converters silently emitted a request the upstream is guaranteed to
      reject. Both OpenAI Chat and Responses → Claude conversions now return
      sharedclaude.ErrMissingMaxTokens when no path (client value, default
      hook, thinking-adapter floor) supplied one. Unreachable in the host,
      which always configures the hook.
      
      Host side, claude.default_max_tokens now rejects negative values at the
      option API before persisting — they would wrap into huge unsigned values
      during conversion. Zero stays allowed: the current API treats
      max_tokens: 0 as cache pre-warming.
      
      * fix: make Gemini safety settings read path race-free
      Calcium-Ion committed
    • fix: allow Advanced Custom Responses Compact · f51dd4d8
      close #6461
      CaIon committed
    • feat: add New API channel support · 398cdafe
      CaIon committed
  2. 26 Jul, 2026 4 commits
  3. 25 Jul, 2026 10 commits
    • feat: support Tencent TokenHub API key via OpenAI-compatible protocol (#6232) · 08f88d25
      * feat: support tencent tokenhub api key via openai-compatible protocol
      
      * fix: use tokenhub base url for tencent api key channels
      
      * test: cover tencent key-format dispatch and add TokenHub key prompt locales
      feitianbubu committed
    • fix(json-code-editor): remove opaque line-number layer background hiding editor content · ae17f274
      The line-number layer spans the full editor, so giving it an opaque
      background and raised z-index covered the highlighted content. Reverts
      the gutter background added in 88868002f; the horizontal-scroll
      gutter overlap it targeted returns as a known cosmetic issue.
      CaIon committed
    • perf(json-editor): unify admin JSON editing experience (#6421) · eb4a1bd1
      * perf(json-editor): improve JSON editing experience
      
      - integrate Yace for syntax highlighting, history, indentation, auto-closing, and smart line breaks.
      - add copy support, cursor location feedback, and synchronized content and line-number scrolling.
      - extract JSON editor utilities and cover key interactions with unit tests.
      
      * perf(system-settings): improve JSON configuration editing
      
      - replace raw JSON textareas with the shared editor for highlighting, validation, copy, and formatting.
      - preserve field-specific examples and make placeholders visible through the transparent editor layer.
      - remove duplicate formatting controls while keeping existing form validation and save behavior.
      
      * perf(json-editor): standardize JSON inputs across admin settings
      
      - replace pure JSON textareas with the shared editor across system settings and channel workflows.
      - preserve form focus, validation, placeholders, and visual or JSON editing modes.
      - add happy-dom component coverage for form bindings, controlled updates, and formatting.
      
      * fix(json-code-editor): address accessibility review findings
      
      - Drop the unconditional aria-label that overrode every field's
        label-derived accessible name; add an optional ariaLabel prop and
        set it at call sites without an associated label
      - Associate standalone Labels via htmlFor/id in channel-affinity views
      - Hide the highlight mirror and line-number layers from the
        accessibility tree (aria-hidden)
      - Give the line-number gutter an opaque background so horizontally
        scrolled code no longer slides under it
      - Degrade to no scroll sync instead of destroying the editor when the
        line-number layer is not found
      QuentinHsu committed
    • fix(web/channel): stabilize inline priority updates (#6415) · a0d0e504
      * fix(channel): debounce inline priority updates
      
      * fix(channel): commit spinner edits only on Enter or focus leave
      
      Blurring the inline edit input to the +/- buttons flushed the pending
      priority update immediately, bypassing the container focus-containment
      check and defeating the debounce. Commit now happens via the container
      blur handler or explicitly on Enter. Add unit tests for the priority
      update scheduler.
      
      * fix(channel): preserve row identity when priority updates reorder channels
      RedwindA committed
    • fix: prevent model create from wiping existing pricing for same name (#6365) · 27235a27
      * fix: prevent model create from wiping existing pricing for same name
      
      * fix(models): keep create from wiping pricing for any existing name
      
      Prefilling from the drawer's open-time model name only covered the
      missing-models entry point. Submit deletes the pricing entries for the
      name in the form, which is editable and starts empty from the toolbar
      "Create model" button, so both a hand-typed existing name and a renamed
      prefill still dropped the configured pricing.
      
      Track the name whose pricing was actually read into the form and scope
      the delete-then-readd to it, or to a name the user explicitly priced.
      Editing still clears pricing by emptying the fields, a prefilled create
      does too, and a name the form never loaded is left alone -- which also
      stops an edit that renames onto an existing name from destroying that
      name's pricing.
      
      Read the prefill through one shared readPricingConfig instead of
      duplicating the seven-map parse in both branches, and open the advanced
      section for ratios that are configured as 0 rather than only truthy ones.
      feitianbubu committed
  4. 24 Jul, 2026 3 commits
  5. 21 Jul, 2026 1 commit
    • fix(auth): keep login state on rate-limited or failing token refresh · 17211442
      When the dashboard token refresh endpoint returned 429 (shared
      critical rate limit) the frontend classified it as out_of_sync,
      cleared local auth state, and redirected to /sign-in. The rate limit
      itself is working as intended; the bug is that a temporary rejection
      was treated as a terminal auth failure.
      
      - Treat 429 refresh responses as transient errors on the frontend,
        keeping the session retryable instead of clearing it. Only explicit
        401 or confirmed session mismatch/race exhaustion clears auth state.
      - Return Retry-After on all rate-limited responses (remaining TTL on
        Redis, window duration on the in-memory limiter) so clients can
        back off.
      - Log the underlying error with request context when auth session
        errors map to 500 AUTH_INTERNAL_ERROR, and replace fmt.Println with
        request-scoped logging in the Redis rate limiter error paths.
      
      Fixes #6361
      CaIon committed
  6. 20 Jul, 2026 9 commits
  7. 18 Jul, 2026 4 commits
  8. 17 Jul, 2026 3 commits
    • fix(data-table): update table body immediately when toggling columns (#6253) · dc9aeab9
      DataTableRow's React.memo did not depend on columnVisibility.
      TanStack row references stay stable when visible columns change, so the
      table body did not refresh after View -> Toggle columns until another
      action rebuilt the column definitions.
      
      Capture a visible column id signature (visibleColumnIds) outside the
      memo and compare it, matching the existing isSelected snapshot pattern.
      All tables that use DataTableRow pick up the fix.
      DawnMoon1542 committed
    • fix: add server-side sorting to user list, prevent client-side sort on paged data (#6194) · 506e41c1
      * fix: add server-side sorting to user list, prevent client-side sort on paged data
      
      The user management table applied client-side sorting to the current
      page slice while pagination was handled server-side, causing ID-asc
      views to show pages out of order (e.g. 23-42, 3-22, 1-2).
      
      Backend: add sort_by/sort_order query params to GetAllUsers and
      SearchUsers with a column whitelist for safe ORDER BY generation.
      Frontend: pass sorting state to the API and reset to page 1 on sort
      change. Generic useDataTable hook now disables client-side sorted row
      model and sort UI for tables with manual pagination but no server-side
      sort handler.
      
      * fix: add id tie-breaker to non-unique sort columns, remove side effect from state updater
      
      Append secondary ORDER BY id DESC when sorting by non-unique columns
      (quota, created_at, etc.) to prevent row duplication/skipping across
      OFFSET pages.
      
      Move onPaginationChange out of setSorting updater to avoid side effects
      inside a pure function (React Strict Mode double-invocation safety).
      DawnMoon1542 committed
  9. 14 Jul, 2026 1 commit