Skip to content

Releases: youssefvdel/opengate

v0.8.0 — Anthropic API, wreq-js rewrite, tool fixes

Choose a tag to compare

@youssefvdel youssefvdel released this 25 Jun 11:45

Features

  • feat: Anthropic-compatible /v1/messages endpoint — streaming, thinking, tool calls, Claude Code support
  • feat: Replace wreq-js with BoringSSL native worker (wreq-worker.mjs) — eliminates Rust tokio epoll crashes
  • feat: Browserless fetch mode — direct HTTP fetch instead of Playwright for accounts with valid cookies

Tool Call Fixes

  • fix: Tool_use SSE format matches Anthropic spec exactly (content_block_start with empty input: {}, input_json_delta events, content_block_stop)
  • fix: Strip XML artifacts (<function=...>) from text_delta emission — prevents Claude Code from double-parsing tool calls from text
  • fix: Structured tool descriptions in system prompt as textual fallback for models that ignore local_mcp
  • fix: Clarify context.txt is a Qwen cloud file, not local filesystem — stops agents trying to read it locally

Session & Reliability

  • fix: Stream idle timeout on handleAnthropicStream (STREAM_IDLE_TIMEOUT_MS, default 60s) — prevents accounts stuck in-flight when upstream hangs
  • fix: Close wreq-js sessions on all error paths (no more leaks on failures)
  • fix: toolNames dashboard log reads t.function?.name || t.name (no more null)

Steamlining

  • chore: Remove startup log line "Claude Code: Proxy enabled"
  • chore: Add CLAUDE_CODE_PROXY env var toggle

v0.7.2

Choose a tag to compare

@youssefvdel youssefvdel released this 23 Jun 13:15

Fixes

  • fix: close wreq-js sessions after every use — eliminates tokio epoll Bad file descriptor panic
  • fix: close wreq-js sessions in background acw_tc cookie refresh timer
  • fix: close wreq-js sessions on all error paths (no more leaks on failures)

Before

Every request leaked ~5-10 wreq-js sessions (STS token, parse trigger, parse polling, session creation, chat completion). The Rust tokio runtime continued polling on their epoll fds after JavaScript GC'd them, causing: unexpected error when polling the I/O driver: Bad file descriptor

After

All wreq-js sessions are explicitly closed after use. Non-streaming calls close immediately. Streaming calls close when the response stream ends. Zero leaked sessions.

v0.7.1

Choose a tag to compare

@youssefvdel youssefvdel released this 23 Jun 13:07

Changes

  • perf: merge file uploads into single context.txt — halves upload latency (2 sequential file uploads → 1)
  • perf: reduce parse poll timeout from 60s to 5s for small text files
  • perf: add timing log to parse polling for diagnostics
  • fix: update default system prompt to reference context.txt format
  • fix: remove dead applyRequestJitter code (was never called)

v0.7.0 — Browserless Fetch + Pure Node.js bx-ua

Choose a tag to compare

@youssefvdel youssefvdel released this 22 Jun 23:43

Performance:

  • Memory: eliminated Playwright/CDP Chromium daemon (~300-500MB RSS per browser process).
    API calls use wreq-js with zero browser overhead. Playwright browser only for
    cookie refresh (30-min TTL, ~7s every 30 min).
  • bx-ua generation: 0.1ms vs Playwright extraction ~7s. Cold start eliminated
    (pure JS, no VM bootstrap).
  • Session management: wreq-js TLS/HTTP2 sessions instead of CDP debug protocol.
    No Chromium per-account overhead.

Fixes:

  • Issue #22: session acquire timeout. getBasicHeaders() no longer calls
    initPlaywright(). Cookies from saved profiles, bx-ua from Node.js generator.
    Playwright only used for periodic cookie refresh, not for header extraction.
  • Health check test: removed stale playwright assertion.

CI: 112 tests, 0 failures. All checks pass (Biome, tsc, test).

Changes since v0.6.0 (22 files, +2225/-547):

Pure Node.js bx-ua Generator (new):
src/services/bxUaGenerator.ts — real-format tokens without Playwright
"231!" + base64(900 bytes) = 1204 chars, SHA-256 fingerprint + HMAC filler
15-min TTL cache, 9/9 tests pass

Browserless Fetch Stack (new):
src/services/browserlessFetch.ts — wreq-js TLS/HTTP2 impersonation (Chrome 142)
src/services/bxTokenExtractor.ts — bx-umidtoken from sg-wum endpoint
src/services/tokenCache.ts — generic TTL cache
src/services/fireyejsRunner.ts — token gen + cookie refresh

Removed (Playwright/CDP):
getBasicHeaders() no longer calls initPlaywright() — no Playwright for headers
Removed extractBxUaFromBrowser() — no more Playwright for bx-ua
Removed dead getQwenHeaders import and buildRequestHeaders from qwen.ts
Simplified playwright.ts (-45 lines), qwen.ts (-218 lines)
Stripped CDP/Chrome dashboard code (accounts.js -25 lines)
src/index.tsx simplified (-295/+0 net)

Updated:
sessionPool.ts — wreq-js sessions instead of CDP
qwenModels.ts, qwenFileUpload.ts — browserlessFetch instead of Playwright
package.json — added wreq-js dependency

v0.6.0

Choose a tag to compare

@youssefvdel youssefvdel released this 22 Jun 18:28

v0.6.0 — CDP Integration, Session Pool Stability, File Uploads

This release introduces full CDP (Chrome DevTools Protocol) integration to bypass AliCloud WAF and baxia bot detection, major session pool stability fixes, automatic large-payload file uploads, and Chromium memory optimization.

Highlights

  • CDP Integration: All Qwen API calls route through real Chrome via CDP, automatically bypassing WAF/baxia bot detection without manual header capture
  • Zero Setup: Auto-launches headless Chrome on port 26404 — no manual configuration needed
  • Session Pool Stability: Fixed hanging acquires, double-release bugs, zombie sessions, and inFlight tracking leaks
  • File Uploads: Automatically uploads large payloads as Qwen file attachments instead of truncating
  • Chromium Memory: 11 memory-reduction flags keep Chrome under 512MB headless

Features

  • Route Qwen API through real Chrome via CDP to bypass baxia WAF
  • Per-account CDP browser contexts with proper startup ordering
  • Headless detection evasion, UA rotation, and improved warmup
  • Route ALL API calls through Node.js fetch — removed browser CDP Fetch domain
  • CDP Fetch domain interception for large request bodies + FAIL_SYS_USER_VALIDATE handling
  • Bot detection logging and account routing fixes
  • Auto-upload large payloads as Qwen file attachments at token limit
  • Keep latest user message inline, upload only history as file
  • Unlock timestamp in throttle logs and API responses
  • XML tool result format, .txt file uploads, updated system prompt with Chromium memory flags
  • Typed config with password master key, health endpoint, rate limiting

Fixes

  • Session Pool: Prevent hanging acquires, empty stream responses, browser context leaks (orphan processes)
  • Throttling: Auto-switch accounts on rate limit, remove prewarm pool, persist throttle across restarts, release session on stream timeout
  • CDP: Fix streaming hang for large bodies, two-phase body storage for 132KB+ requests, fire-and-forget CDP fetch, store profileCookies for Node.js fetch
  • File Uploads: Use natural user message for payload reference, upload full conversation context, deduplicate upload logic
  • Auth: Account auth architecture — throttle on bot detection, timeout skip, LSP connection fixes, login flow, CDP init, system reminder handling
  • Dashboard: Loads when API_KEY is set, CDP status display
  • Captcha: Handle Qwen CAPTCHA detection (FAIL_SYS_USER_VALIDATE)
  • Streaming: One-chunk buffer prevents XML tool call leaks across SSE chunk boundary
  • Stability: Stray TypeScript as-any statements, missing browser context state lookup, Playwright browser install + robust watchdog startup

Performance

  • Streaming parse optimization + sliding window fix
  • Skip filter pipeline when inside tool call block (depth > 0)

Refactoring

  • Remove dead toolResultContents field across pipeline
  • Remove logs page from dashboard

Tests

  • Prevent throttleAccount tests from touching real .qwen/accounts.json
  • Avoid API_KEY env override in getAll test
  • Clean up test artifacts after run

Quality

  • Biome format fixes, dead code removal, docs audit
  • Remove console.log from cdpClient.ts
  • Update stale documentation to match current codebase

Full Changelog: v0.5.0...v0.6.0

v0.5.1

Choose a tag to compare

@youssefvdel youssefvdel released this 16 Jun 01:22

What's Changed

Features

  • Show unlock timestamp in throttle logs and API responses

Bug Fixes

  • Auto-switch accounts on rate limit
  • Non-streaming path now extracts local MCP tool calls
  • Fix emittedToolCallCount index for concurrent tool call SSE events
  • Remove prewarm pool + persist throttle across restarts
  • Delete stale prewarmed sessions from Qwen servers
  • Release session on stream timeout (chat leak)
  • Remove top-level tools from Qwen payload to preserve full thinking
  • Fix answer content lost with thinking_format=full
  • Full thinking_format support with real-time reasoning_content streaming
  • Remove timeout error message from client, silently terminate with [DONE]
  • Dedup feature_config + switch thinking_format to full
  • Delete Qwen session immediately after response (was 60s delay)
  • Always write [DONE] on error paths, prevent SSE client hang
  • Real error logging, thinking capture, upstream SSE error detection

Performance

  • Skip filter pipeline when inside tool call block (depth > 0)
  • Streaming parse optimization + sliding window fix

Refactor

  • Remove dead toolResultContents field across pipeline

Tests

  • Fix getAll test env var collision in CI
  • Delete throttleAccount test that wrote test data to real accounts.json

CI

  • Switch CI from setup-node/npm to oven-sh/setup-bun/bun

Chores

  • Cleanup reports/docs, thinking format improvements
  • Bump version to 0.5.1

v0.5.0

Choose a tag to compare

@youssefvdel youssefvdel released this 13 Jun 23:37

What's New in v0.5.0

Fixed

  • Stream Idle Timeout Hang: Upstream silence no longer hangs the client indefinitely. Catches timeout gracefully, writes error SSE event + [DONE], logs to dashboard. Default timeout 45s, configurable via STREAM_IDLE_TIMEOUT_MS.
  • Tool Call Content Leak: Streaming tool call XML fragments (<function=, =filePath>, -edit) no longer leak into emitted content. Uses toolCallDepth state counter + per-chunk detection.
  • Timing-Safe API Key: Config route now uses constant-time comparison (safeCompare) for API key check.
  • Dashboard Script Injection: Fixed critical bug where serveHtml broke all <script src="..."> tags when injecting window.APP_VERSION.

Changed

  • Data-Driven Stripping: All tag names centralized in src/utils/tagNames.ts. TOOL_CALL_KEYWORDS, THINK_TAG_NAMES, TOOL_RESULT_KEYWORDS arrays drive regex construction in all stripping sites. No hardcoded regex patterns.
  • Deduplication: Think tag regex consolidated from 5 sites → 1 shared. Newline normalization unified everywhere. Removed 250+ lines of dead code (json.ts, stripStreamingDelta, repairMalformedJson, unused re-exports).
  • Performance: END_TAG_PATTERNS hoisted to module-level. IDLE_TIMEOUT_MS hoisted out of hot loop. Short-circuit guards added to cleanThinkTags and parseXmlToolCalls.
  • Better Diagnostics: JSON parse errors log raw data. Stream errors captured in both console and dashboard log.

Full changelog: https://github.com/youssefvdel/qwen-gate/blob/v0.5.0/CHANGELOG.md

v0.4.0

Choose a tag to compare

@youssefvdel youssefvdel released this 11 Jun 16:45

Authentication & Account Management

  • Refactored authentication to read tokens exclusively from Chromium browser profiles instead of cookie files (src/services/auth.ts, src/services/accountManager.ts)
  • Removed cookie folder system -- no more qwen_profile/cookies/ directory fallback (src/services/accountManager.ts)
  • Added browser profile authorization on account creation via openBrowserProfile before falling back to API login (src/services/accountManager.ts) (@studi929)
  • Added loadCookiesFromProfile function to extract tokens from persistent Chromium profiles (src/services/auth.ts) (@studi929)
  • Added parallel profile/cookie extraction at startup (batch 3 concurrent) with phased initialization (src/services/auth.ts)
  • Added automatic cookie refresh from Chromium profile on every boot (src/services/browserProfiles.ts)
  • Fixed refresh_token extraction and saving during profile-based auth (src/services/browserProfiles.ts, src/services/auth.ts)
  • Fixed Token TTL showing 0 for session cookies from browser profiles (src/services/browserProfiles.ts)
  • Added HOST config option for binding the server to a custom hostname (src/services/configService.ts)
  • Added validation in ConfigService for PORT range and negative values for numeric config keys (src/services/configService.ts)
  • Added warning on unknown config keys in config.json (src/services/configService.ts)
  • Removed double inFlight increment in pickAccount() on the account manager side (src/services/accountManager.ts)
  • Made pickAccount() async with mutex-guarded account selection and inFlight tracking (src/services/accountManager.ts)
  • Made getTokenWithAccount() async to match async pickAccount() (src/services/accountManager.ts, src/services/playwright.ts)
  • Fixed rate limiting on account add/delete endpoints (src/routes/accounts.ts) (@studi929)
  • Replaced loginFresh call in account login route with openBrowserProfile + loadCookiesFromProfile (src/routes/accounts.ts) (@studi929)
  • Updated manual login (autofill) flow to open non-headless browser and poll for auth completion (src/routes/accounts.ts) (@studi929)
  • Added AES-256-GCM encryption for stored account passwords using API_KEY or machine-based key derivation (src/services/accountManager.ts)
  • Added migrateFromOldPaths() to move accounts from qwen_profile/ to .qwen/ directory (src/services/accountManager.ts)
  • Changed account watcher to watch .qwen/accounts.json instead of the old cookie directory (src/services/accountManager.ts)
  • Added removeAccountContext and removeAccountContext to properly clean up Playwright contexts on account removal (src/services/playwright.ts, src/services/accountManager.ts)
  • Added watcher retry logic with debounced timer for filesystem watch failures (src/services/accountManager.ts)
  • Fixed getAccountByEmail to normalize email casing before lookup (src/services/accountManager.ts) (@studi929)
  • Fixed silent autoFillLogin export removal -- removed unused function (src/services/browserProfiles.ts)
  • Migrated all console.error/warn calls to logStore.log in auth-related services (src/services/loginHelpers.ts, src/services/tokenRefresh.ts, src/services/auth.ts, src/services/browserProfiles.ts, src/services/accountManager.ts) (@studi929)
  • Fixed auth navigation to only clear specific auth cookies instead of ALL cookies (src/services/loginHelpers.ts) (@studi929)
  • Added JSON response body token extraction in signin route interception (faster than set-cookie headers) (src/services/loginHelpers.ts) (@studi929)
  • Replaced blind 2s sleep with polling loop (10 attempts, 500ms intervals) in temp context login (src/services/loginHelpers.ts) (@studi929)
  • Reduced auth page timeouts from 30s to 20s and selector waits from 15s to 10s (src/services/loginHelpers.ts) (@studi929)
  • Fixed loginFresh to try fetch-based login before browser-based login (src/services/auth.ts) (@studi929)
  • Added autoLoginAllAccounts to run logins in parallel instead of sequential with delays (src/services/auth.ts)
  • Removed loadSavedCookies function -- no longer reads from cookie files (src/services/auth.ts)
  • Fixed saveCookies to write token persistence to .qwen/tokens/ directory instead of cookie files (src/services/auth.ts)
  • Updated auth fallback in refreshAccountCookies to skip throttling when a valid token exists in memory (src/services/playwright.ts)
  • Added JWT token injection as cookie in browser context during cookie refresh (src/services/playwright.ts)
  • Changed cookie refresh interval from 30s to 120s with jitter (src/services/playwright.ts)

Dashboard & UI

  • Removed API_KEY-based authentication from dashboard log, health, metrics, account stats, and config read endpoints (src/routes/dashboard/dashboardRoutes.ts)
  • Added conditional bearer auth on admin-only endpoints (reload accounts, delete-all-chats) only when API_KEY is configured (src/routes/dashboard/dashboardRoutes.ts)
  • Sanitized sensitive data in dashboard log entries -- mask emails, truncate large content, strip credentials (src/routes/dashboard/dashboardRoutes.ts)
  • Exposed config without API_KEY value in the /api/config endpoint (src/routes/dashboard/dashboardRoutes.ts)
  • Reformatted overview.css from single-line to multi-line with proper indentation (src/routes/dashboard/public/overview.css)
  • Changed overview grid layout from 2fr 1fr to 3fr 2fr (src/routes/dashboard/public/overview.css)
  • Added max-height: 100vh and max-height: 80vh constraints to panels and system logs container (src/routes/dashboard/public/overview.css, src/routes/dashboard/public/accounts.css)
  • Added scrollable system logs container with overflow-y auto (src/routes/dashboard/public/overview.css)
  • Fixed system logs to append new entries via insertAdjacentHTML instead of full innerHTML replacement (src/routes/dashboard/public/overview.js)
  • Added notification dedup -- caps at 5 visible notifications at a time (src/routes/dashboard/public/overview.js)
  • Added createPoller utility with exponential backoff on failures and pause-on-hidden (src/routes/dashboard/public/shared.js)
  • Replaced all setInterval pollers with createPoller for adaptive polling across dashboard pages (src/routes/dashboard/public/overview.js, src/routes/dashboard/public/logs.js, src/routes/dashboard/public/accounts.js, src/routes/dashboard/public/network.js)
  • Added toast limit to 5 on accounts page (src/routes/dashboard/public/accounts.js)
  • Fixed login button state management -- removed stale setTimeout resets (src/routes/dashboard/public/accounts.js) (@studi929)
  • Added active poll timer tracking to prevent duplicate pollAuth intervals (src/routes/dashboard/public/accounts.js)
  • Removed API_KEY from logs page fetch headers and EventSource URL (src/routes/dashboard/public/logs.js)
  • Added hidden entries buffer and Load More functionality for log entries (src/routes/dashboard/public/logs.js)
  • Fixed network.js duration classification -- changed threshold from 3000ms to 500ms for slow (src/routes/dashboard/public/network.js)
  • Added textarea support in settings form with proper styling and box-sizing (src/routes/dashboard/public/settings.css)
  • Removed inline textarea styles in favor of CSS classes (src/routes/dashboard/public/settings.js)
  • Moved Delete All Chats button to a separate Danger Zone section with warning styling (src/routes/dashboard/public/settings.js)
  • Added confirmation modal for delete-all-chats with progress display (src/routes/dashboard/public/settings.js)
  • Added error handling for delete-all-chats HTTP failures in the modal flow (src/routes/dashboard/public/settings.js)
  • Added escape for single quotes and backticks in escHtml (XSS hardening) (src/routes/dashboard/public/shared.js)
  • Changed modal visibility to use hidden CSS class instead of inline style.display (src/routes/dashboard/public/settings.js, src/routes/dashboard/settings.ts)
  • Added toast limit cap on settings page (src/routes/dashboard/public/settings.js)

API & Streaming

  • Added per-message size validation (100KB limit) to prevent OOM during token estimation (src/routes/chat.ts) (@studi929)
  • Moved logIncomingRequest call removal -- no longer logs every request body (src/routes/chat.ts)
  • Fixed pickAccount to be async in session setup, with proper decrementInFlight on acquire failure (src/routes/chat.ts) (@studi929)
  • Added error type and code to error responses (src/routes/chat.ts) (@studi929)
  • Fixed createQwenStreamWithRetry to forward toolChoice parameter (src/routes/chat.ts, src/routes/chatHelpers.ts) (@studi929)
  • Fixed buildQwenMessages to serialize complex parameter values with JSON.stringify instead of String() (src/routes/chatHelpers.ts) (@studi929)
  • Limited think/thought tag patterns in buildQwenMessages -- removed tool_call, tool_use, function_call, tool from think tag stripping (src/routes/chatHelpers.ts) (@studi929)
  • Removed createLogEntry function -- consolidated into caller (src/routes/chatHelpers.ts)
  • Fixed detectCumulativeChunk with multi-size fingerprint matching for robust delta detection (src/routes/chatHelpersCore.ts) (@studi929)
  • Fixed getSnapshotDelta to handle cases where cleaned content becomes shorter than previous snapshot (src/routes/chatHelpersCore.ts) (@studi929)
  • Restricted think tag patterns in cleanThinkTags -- only think, thinking, thought (removed tool_call, tool_use, function_call, tool) (src/routes/chatHelpersCore.ts) (@studi929)
  • Added history trim to ToolSpamGuard to prevent unbounded growth (src/routes/chatHelpersCore.ts) (@studi929)
  • Added periodic cleanup of pendingCorrections map (trim to 500 entries every 5 minutes) (src/routes/chatHelpersCore.ts) (@studi929)
  • Made processToolCallsThroughGuard accept configurable maxToolCalls parameter (src/routes/chatHelpersCore.ts) (@studi929)
  • Fixed non-streaming delta processing to only parse new content since last parsed position (src/routes/chatNonStreaming.ts) (@studi929)
  • Added lastParsedPosition tracking in non-streaming processor (src/routes/chatNonStreaming.ts) (@studi929)
  • Added handling for local_tool ph...
Read more

v0.3.1

Choose a tag to compare

@youssefvdel youssefvdel released this 08 Jun 17:20

v0.3.1 — XML Tool Calling & Install Fix

  • Added XML tool call parser for Qwen's native <function=name> format
  • New accounts get native tools/memory disabled on add
  • Install script simplified: no pipes, no silent flags, always runs npm install
  • Fixed raw.githubusercontent.com CDN cache issues via release tag

v0.3.0

Choose a tag to compare

@youssefvdel youssefvdel released this 08 Jun 15:47

v0.3.0 — Cleanup & Hardening

Removed

  • Echo detection system — StreamingEchoFilter, ToolResultEchoFilter, and all related config keys
  • XML strippingxmlStripper.ts deleted; content passes through as-is
  • 12 stale test/data files (study captures, log replays, dead tests)

Changed

  • Qwen request/response logging now respects SAVE_REQUEST_LOGS flag (default: off)
  • Default MCP client name: gatewayqwengate
  • System prompt no longer promises automatic stripping of artifacts
  • Dashboard settings/logs UI cleaned of echo references
  • Red ASCII art startup banner with green bullet points

Fixed

  • All tsc --noEmit errors resolved
  • createQwenStreamWithRetry type mismatch (string → QwenMessage[]) — fixes messages.map is not a function crash
  • aislop score: 95/100, zero source-tree findings

Tech

  • Version bumped from 0.2.0 → 0.3.0