Skip to content

feat:/fix: - #61

Open
elan40213-eng wants to merge 15 commits into
Vanszs:mainfrom
elan40213-eng:main
Open

feat:/fix:#61
elan40213-eng wants to merge 15 commits into
Vanszs:mainfrom
elan40213-eng:main

Conversation

@elan40213-eng

Copy link
Copy Markdown

Hi! I’ve tweaked a few features to suit my needs

Model aliases in /v1/models. You can assign aliases to specific models; they are now displayed under their own name, without the provider prefix. When {"model": "my-alias"} is sent from any OpenAI-compatible client, the router will resolve it internally and then return the alias name in the response and in every stream fragment. Aliases pointing to disabled models are excluded from the list, and the cache is cleared immediately after any alias change, rather than after the TTL expires.

Default system prompt. This new parameter contains text that is added to the system slot of any chat request if it does not already contain a prompt. It works with OpenAI, Claude and Gemini request formats and is triggered early enough to allow other system prompt features to be added after it. Disabled by default

Access Control List (ACL) for models at key level. API keys can now restrict which models they are permitted to call, in addition to existing restrictions by provider and combination. A selector is provided in the control panel for this purpose. The corresponding check is now applied universally, including on public endpoints without a configured key.

Caching of the Google project ID. The cached ID is now valid for 30 days instead of 1 hour, as it is tied to the account rather than the token. During a scheduled token refresh, the ID is retrieved from the database rather than being re-requested from the Google endpoint for registration.

Gemini CLI request handling. Fields rejected by the Cloud Code Assist API are removed before the request is sent. The ‘Thinking’ visibility is now mapped to a native configuration field rather than being ignored. Tool schemas are sent in a format that the API can actually read.

‘Thinking’ output formats for NVIDIA NIM. Each model family now uses its own native format for outputting reasoning results, rather than a single common format for all.

DuckDuckGo search. It has been registered, and request headers have been rewritten to match those of a real browser, so that DuckDuckGo no longer throttles its bandwidth.

Headroom detection. Checking for the presence of the Headroom binary previously blocked the control panel for over 20 seconds if it was not installed. The results are now cached, and the slow search path is only triggered when necessary.

Control Panel optimisation. The profile page has been rewritten to a smaller file, an ACL key selector has been added, and several user interface elements now support keyboard navigation.

Each new database column allows null values, and each new setting is disabled by default, so existing deployments will continue to work without any changes. Compiled and tested from start to finish on my VPS

…ojectId persistence, DuckDuckGo browser profile

- ModelRow: empty draft on Save now deletes the alias instead of silently no-op
- allowedModels: isModelAllowed enforces global list even without apiKeyInfo;
  appendUserAliasEntries surfaces bare alias names; cache invalidated on
  alias/disabled mutations
- v1/models: alias entries pass through with owned_by=alias
- chat.js + chatCore + stream/nonStreaming: echo client-facing model id
  (alias) back in /v1/chat/completions response.model and SSE chunks
- projectId: cache TTL 30d bound to Google account not OAuth token;
  skip re-fetch when DB already has projectId (seedProjectIdCache)
- settingsRepo + systemInject + chatCore: injectDefaultSystemPrompt only
  when request has no system message yet
- DuckDuckGo: undici Agent (HTTP/2) + stable Chrome 131 header set
  (Sec-CH-UA client hints, full Accept)、 replacing the bot UA
- registry/index.js: register duckduckgo provider
- duckduckgo.png icon
@Vanszs

Vanszs commented Jul 25, 2026

Copy link
Copy Markdown
Owner

hi @elan40213-eng thanks for the pr, i will review it asap, please keep the pr open

@mahdiwafy

Copy link
Copy Markdown

Found an issue while merging this locally: package.json adds @tailwindcss/oxide-wasm32-wasi under dependencies. That package is wasm32-only, and npm rejects it with EBADPLATFORM on x64 hosts (e.g. the Docker builder) — npm install fails outright there. The native oxide-linux-x64-musl binary is what's actually used at build time on those platforms, so the wasm variant should be skippable rather than required.

Suggested fix — move it to optionalDependencies (same pattern already used for better-sqlite3 in this repo):

   "dependencies": {
     ...
-    "@tailwindcss/oxide-wasm32-wasi": "4.3.0",
     ...
   },
   "optionalDependencies": {
+    "@tailwindcss/oxide-wasm32-wasi": "4.3.0",
     "better-sqlite3": "^12.6.2"
   },

Also worth double-checking on merge: this PR touches src/app/api/combos/route.js and src/lib/db/repos/combosRepo.js (adding alias) — #58 touches the same two files/functions (adding context_length). Both changes are compatible, just a straightforward text conflict for whichever merges second (left the same note on #58).

The wasm32 fallback was in the main dependencies block with a pinned 4.3.0
version, causing npm install to fail with EBADPLATFORM on x64 hosts (and
any non-wasm32 CPU). Move it to optionalDependencies mirroring the
better-sqlite3 pattern and bump the spec to ^4.3.3 to match the resolved
@tailwindcss/oxide version. Drop the non-standard comment_better_sqlite3
metadata key while here.
Hardcoded dev origins forced every contributor into the same localhost
setup. Read VANS_ALLOWED_DEV_ORIGINS (comma-separated) with the prior
127.0.0.1,localhost as the default. Prod is unaffected — Next 16
ignores allowedDevOrigins outside dev mode.
Race: resolvePrivilegedUserId().then(...) was scheduled without await in
transformRequest, so the first request always went out without the
x-gemini-api-privileged-user-id header (the .then microtask could not
drain before buildHeaders ran synchronously). Fix:
  - Prewarm the cache at module load so it is ready before any request.
  - Make transformRequest await resolvePrivilegedUserId() so the header
    is present on the very first request. Await is safe because
    BaseExecutor.execute now wraps transformRequest in
    await Promise.resolve(...), keeping the sync-return contract for
    every other executor.

Mutation: stripOpenAILeakFields/applyIncludeReasoningToGemini mutated the
input body in place, leaving loggers, error DB saves, and the 401/403
retry path reading a stripped body instead of the client's original.
Fix: structuredClone(body) at the start of transformRequest so the
original translatedBody stays pristine for downstream consumers.
…branch

webSearchInject.js (125 lines) was never imported by chatCore, chat, or
any executor — the live web-search path lives inline in chat.js. Drop
the orphan module. Simplify the redundant provider.id === 'duckduckgo'
check in search/index.js (registry already sets executor: 'duckduckgo').
Remove the unused bodyHasReasoning variable in chat.js that nothing read.
The /^[a-zA-Z0-9_.\-]+$/ regex and its hint strings were copied across
two API routes and the dashboard page. Extract COMBO_NAME_REGEX,
COMBO_NAME_HINT, COMBO_ALIAS_HINT into src/shared/constants/comboValidation.js.
Behavior unchanged: same validation, same error messages, same status codes.
Catch-block console.log calls in API routes wrote errors to stdout
instead of stderr, mixing diagnostics with normal output. Convert them
to console.error across providers/[id]/models, v1beta/models
([GEMINI_NATIVE] telemetry), keys, models/alias, models/disabled,
proxy-pools/[id], and cli-tools/claude-settings. Remove the stray
console.log('Deno deployUrl:', deployUrl) in proxy-pools/deno-deploy
that leaked every freshly-minted relay URL to stdout.
When PUT /api/keys/[id] received an allowedModels/allowedProviders/
allowedCombos/allowedKinds value that was neither null nor an array
(string, object, number), it silently coerced to null — meaning
'all allowed' — masking caller bugs as over-permissive defaults.
Default unexpected types to [] (deny-all) for all four ACL fields,
matching the documented contract: null = all, [] = none, [...] = specific.
The system-prompt save handler swallowed all failures silently (empty
catch), leaving users with no indication the save failed. Reuse the
file's existing {type, message} status pattern to surface errors next
to the Save button. Remove the unused isDark destructure from
useTheme() (never referenced in the file).
The chromium executablePath was pinned to /home/vanszs/.cache/
ms-playwright/chromium-1228/chrome-linux64/chrome — one contributor's
absolute home path that fails on every other machine. Read
VANS_ZCODE_CHROMIUM_PATH from the environment; pass undefined to let
playwright-core use its own channel discovery when the env var is unset.
The dev prewarm script fell back to '123456' when VANS_PREWARM_PASSWORD
was unset, silently authenticating with the default dashboard password
in any environment that forgot to set the env var. Fail closed: if the
env var is missing, print a clear error and exit non-zero so the
operator sets it explicitly.
The per-process _binCache/_pyCache/_extrasCache never exposed an
invalidation path, so installing headroom-ai while the server was
running left the dashboard reporting 'not installed' until process
restart. Export invalidateHeadroomCaches() so the install endpoint can
reset the probes after a successful install.
Extend the shared COMBO_NAME_REGEX to ComboFormModal and the
media-providers combo edit page, the two remaining copies of the
/^[a-zA-Z0-9_.\-]+$/ regex that were protected by the first DRY pass.
Behavior unchanged.
The /api/models response is always { models: [...] } by convention, so
the Array.isArray(data) fallback at line 526 was dead code reachable
only if the endpoint changed shape. Remove it. Restore 'No providers'
capitalization to match the adjacent 'No models' badge.
The commit that converted login-page strings from inline Bahasa to
inline English left Indonesian-cookie users seeing English, because
no corresponding keys existed in public/i18n/literals/id.json and the
runtime DOM translator only matches known English source strings. Wrap
the placeholder, dispatch error fallbacks, button label, and OIDC
fallback in translate() from @/i18n/runtime (attributes and
state-driven strings are not reached by the MutationObserver-driven
DOM walker). Add the missing English keys to id.json, using the
pre-commit Bahasa strings as the Indonesian translations.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants