Skip to content

Releases: sena-labs/Open-WebUI-Pipe-OpenRouter

v1.10.4 — Funding to Ko-fi

31 May 20:25

Choose a tag to compare

Funding source switched to Ko-fi only: https://ko-fi.com/senalabs

  • .github/FUNDING.yml rewritten to ko_fi: senalabs
  • funding_url in function.json and the module-level frontmatter docstring point to https://ko-fi.com/senalabs
  • GitHub Sponsors link removed

No code change. All 939 unit tests still green.

v1.10.3 — Portal Upload Fix (frontmatter refresh)

31 May 18:53

Choose a tag to compare

Patch release that supersedes v1.10.2 and fixes the openwebui.com portal upload for real.

What v1.10.2 got wrong

Swapped the function id to openrouter-pipe on the assumption the portal expected dashes. OWUI source proves otherwise — src/lib/utils/index.ts:

export const nameToId = (name: string): string =>
  name.normalize('NFD')
      .replace(/[\u0300-\u036f]/g, '')
      .replace(/[^\w]+/g, '_')   //  \w = [A-Za-z0-9_] → dashes → underscores
      .replace(/^_+|_+$/g, '')
      .toLowerCase();

OpenRouter Pipeopenrouter_pipe. Every existing community pipe under /f/<user>/<slug> uses underscores. v1.10.3 reverts to the historical id.

The actual portal error

backend/open_webui/utils/plugin.py:extract_frontmatter parses the module-level docstring at the top of openrouter_pipe.py against ^\s*([a-z_]+):\s*(.*)$ and ships those keys to the portal preview. The docstring still claimed version: 1.9.0 and a description from before the v1.10.x image / video / audio output flows, so the portal surfaced the stale/missing keys as a JavaScript undefined tooltip.

Fixed in 1.10.3

  • function.json id reverted to openrouter_pipe, version → 1.10.3.
  • Module-level frontmatter docstring rewritten: version: 1.10.3 + a v1.10.x-accurate description (image-gen, video-gen, audio-gen embed mechanics, SSRF-guarded media downloads, 99.3% icon coverage, MAX_TOOL_ITERATIONS, encrypted UserValves keys, atomic routing-set swap). Unicode arrow replaced with .. to avoid non-ASCII edge cases in the portal's tooltip renderer.
  • Docstring examples in _clean_model_id and _sync_model_icons reverted to openrouter_pipe.openai/gpt-4o.

Migration for v1.10.2 testers

If you tagged or installed 1.10.2 between releases your OWUI DB has a stranded function row under openrouter-pipe. To clean up:

  1. Copy your Valves config.
  2. Admin Panel → Functions → delete the openrouter-pipe entry.
  3. Install/update openrouter_pipe to 1.10.3.
  4. Paste your Valves config back.

No chat history is lost (it is keyed on the model selector entry, not the function row).

Tests

All 939 unit tests still green on Python 3.10–3.13.

v1.10.2 — Function ID Portal-Slug Fix

31 May 17:22

Choose a tag to compare

Patch release fixing the openwebui.com community portal upload.

What changed

function.json id renamed from openrouter_pipe to openrouter-pipe so it matches the slug the portal auto-generates from the listing title ("OpenRouter Pipe"). The portal previously rejected the underscored manifest with an undefined error.

Breaking change for existing Admin-Panel installs

Open WebUI keys functions by ID in its database. After this update:

  • The old openrouter_pipe function row remains active in your DB.
  • The new openrouter-pipe ID will create a fresh function row when re-installed from the portal.

Migration (no chat history is lost — it's tied to the model selector entry, not the function row):

  1. Copy your current Valves configuration.
  2. Uninstall the old openrouter_pipe function from Admin Panel -> Functions.
  3. Install the new openrouter-pipe from the openwebui.com portal (or paste openrouter_pipe.py v1.10.2).
  4. Paste your Valves configuration back.

Tests

All 939 unit tests still green.

Other changes

  • Docstring references in _clean_model_id and _sync_model_icons now show the dash form when illustrating the OWUI manifold prefix (e.g. openrouter-pipe.openai/gpt-4o).
  • 5 test_pipe.py simulations of _function_id and 2 prefix-assertion strings updated to match the new ID.

v1.10.1 — Icon Coverage 99.3%

31 May 13:09

Choose a tag to compare

Patch release covering the 10 icon-system commits between v1.10.0 and now. Live-VPS brand-icon coverage went from 261/408 (64%) to 448/451 (99.3%) — only the three kwaivgi/kling-* models remain on the deterministic letter-SVG fallback because Kuaishou's video team has no public icon source.

Added

  • Layered icon-resolution fallback chain (registry → hyphen-strip → hardcoded → alias → provider-domain → letter-SVG)
  • 41 official brand / HuggingFace-avatar icons hardcoded in _PROVIDER_ICONS
  • USE_PROVIDER_DOMAIN_FAVICON admin valve (default true) — privacy-friendlier than gstatic
  • _generate_letter_icon deterministic last-resort fallback
  • _sync_orphan_db_icons sweep — patches OWUI rows for deprecated/withdrawn models the regular sync skips

Fixed

  • /static/favicon.png now recognised as managed (OWUI 0.4+ server default)
  • Models.{get,update,insert}_model_by_id async on OWUI ≥ 0.4 — new _resolve_maybe_awaitable resolver
  • Provider-domain favicon URLs that returned text/html (SPA shell) for ai21 / bytedance / mancer / openrouter swapped to HuggingFace avatars

Tests

868 → 939 (+71). All green on Python 3.10–3.13.

Migration

No breaking changes. Replace openrouter_pipe.py in Admin Panel → Functions → OpenRouter Pipe, or pull v1.10.1 from GitHub. The icon sync runs automatically on the next pipes() call.

v1.10.0 — Image / Video / Audio Generation + 5-Agent Audit

30 May 21:25

Choose a tag to compare

The definitive OpenRouter integration for Open WebUI — now with full media-generation support and a hardened security/perf surface from a multi-pass audit.

New capabilities

  • Image generation (flux, gemini-image-preview, …) — data: URLs decoded, uploaded to OWUI storage, rendered inline as ![Generated image](/api/v1/files/.../content). Works on stream, non-stream, and native-tool paths.
  • Video generation (google/veo-3.1-*, kwaivgi/kling-*, openai/sora-*, bytedance/seedance-*, minimax/hailuo-*, alibaba/wan-*, x-ai/grok-imagine-video) — async POST /api/v1/videos with polling, MP4 re-hosted, embedded as native <video controls> via OWUI's block-HTML token. Configurable VIDEO_POLL_INTERVAL (5 s) + VIDEO_GENERATION_TIMEOUT (600 s).
  • Audio generation (google/lyria-3-*-preview, openai/gpt-audio*) — pipe injects modalities=[\"text\",\"audio\"] + audio={format,voice} + stream=true automatically. OpenAI's gpt-audio family auto-forced to pcm16 and wrapped in a RIFF/WAVE container (24 kHz mono) so the browser plays it; Lyria gets mp3. New AUDIO_OUTPUT_FORMAT + AUDIO_OUTPUT_VOICE valves.

Security hardening (multi-agent audit batches A–E)

  • SSRF / auth-leak guardpolling_url and unsigned_urls[0] restricted to openrouter.ai (_is_openrouter_url); refuses to send the Authorization bearer to attacker-controlled hosts.
  • Byte-size caps — 100 MiB video / 50 MiB audio, with streaming iter_content + Content-Length early-reject + mid-stream cap.
  • MIME whitelist post-downloadmp4/webm/mov/mkv for video, mpeg/wav/flac/ogg/opus/aac/mp4 for audio; spoofed Content-Type can no longer coerce OWUI's renderer.
  • Citation URL scheme filter_emit_citation_events refuses non-http(s) URLs (closes the javascript: / data: XSS surface).
  • Admin-only ZDRZDR_ENFORCE removed from UserValves; privacy policy is no longer user-overridable.
  • Sanitized internal exceptions — generic Exception no longer leaks raw Python stack traces / file paths to the chat client.

Correctness hardening

  • Body deep-copypipe() deep-copies the body before any modality injection; OWUI's body dict is never mutated (closes a CRIT cross-request leak).
  • Atomic routing-set swap_video_model_ids / _audio_model_ids are frozensets, swapped in one assignment; concurrent pipe() callers never see an empty intermediate set.
  • Lazy populate off the event loop — first request after restart triggers self.pipes() via asyncio.to_thread, gated by _lazy_populated.
  • Resource leakssubmit_resp and per-iteration poll_resp in the video flow are now wrapped in try/finally with close() (previously up to 120 socket leaks per long job).
  • Tool-nonstream clean assistant msg — appends {role, content, tool_calls} only, instead of forwarding the raw upstream dict (which can carry refusal / legacy function_call keys some models reject on re-submission).

Performance

  • HTTPAdapter pool sized for concurrencypool_connections=64, pool_maxsize=64; default urllib3 pool of 10 was a hard limit under load.
  • Cached Authorization headerEncryptedStr.decrypt() (Fernet, ~100 µs) now runs once per ciphertext instead of on every chunk send / poll / footer; auto-invalidates on key rotation.
  • Cached-only credit footer_credit_balance_cached reads from the pre-warmed cache; SSE finalize never blocks on a cold GET /credits.
  • _effective_valves fast path — returns self.valves directly when no UserValves override.
  • _models_cache_valid short-circuit — cheap TTL check before Fernet+SHA256.
  • Hot-path constants_DATA_IMAGE_RE, MIME whitelists, byte caps, _AUDIO_FORMAT_TO_MIME hoisted to module level.

Tests

868 tests (up from 727), all green on Python 3.10–3.13.

Migration

No breaking changes. Existing installs upgrade in place — the new valves all have safe defaults. To pick up the changes, replace openrouter_pipe.py in Admin Panel → Functions → OpenRouter Pipe (or pull the v1.10.0 tag from GitHub).

Full diff: `v1.3.0...v1.10.0` (the previous release tag — code shipped across all intermediate versions documented in CHANGELOG.md).

v1.3.0 — Provider Icon Sync, Audio & Image Output, 340+ Models

07 May 18:58
42b0582

Choose a tag to compare

What's new in v1.3.0

✨ New features

Provider icon sync
Provider logos (OpenAI, Anthropic, Google, Meta, Mistral, DeepSeek, Cohere, Perplexity, Qwen, Microsoft, Fireworks, Moonshot, Amazon) are now written directly into Open WebUI's model database on startup. Icons appear in the model selector without any manual configuration and survive cache refreshes. Five bugs that silently prevented icons from ever appearing after the first load have been fixed.

Audio output support
Models that return audio (e.g. openai/gpt-4o-audio-preview) now surface their transcript as readable text in both streaming and non-streaming mode. Previously these responses produced an empty reply.

Image output support
Models that generate images (e.g. google/gemini-2.5-flash-image-preview) embed the result as a markdown image directly in the chat. URLs are validated — only http:// and https:// schemes are rendered; invalid URLs are silently dropped.

Token usage & cost display
Non-streaming responses append a compact footer — Tokens: 312 in / 84 out · Cost: $0.0004 — when OpenRouter includes usage data. Useful for tracking spend per message without leaving Open WebUI.


🔧 Also in this release (carried from v1.2.0, now officially tagged)

  • Connection pooling via requests.Session — better throughput for multi-turn conversations
  • Model list caching with 5-minute TTL and automatic invalidation when valves change
  • Exponential backoff with jitter on transient network errors (min(2^n + rand, 30s))
  • Fallback model deduplication — silently removes duplicate IDs from FALLBACK_MODELS
  • Base URL validation — Pydantic rejects non-HTTP(S) schemes at save time
  • "error" model guard — selecting the error pseudo-model returns a clear message instead of hitting the API
  • Empty message guard — returns a clear error instead of sending an empty payload
  • Fallback attribution — non-stream replies show Responded by: model-id when a fallback handled the request
  • HTTP 502 auth detection — Clerk 502 errors (malformed API key) caught at model-list time

🐛 Bug fixes

  • _sync_model_icons(): wrong skip condition caused all icons to be silently skipped (any existing icon, including the OWUI default SVG, blocked the update)
  • _sync_model_icons(): race condition — icons written before pipes() returned were overwritten by OWUI's default; now also syncs on cache-hit paths until all icons are confirmed
  • _sync_model_icons(): DB errors no longer mark a model as permanently synced, allowing retry on next request
  • _sync_model_icons(): update_model_by_id no longer clobbers user-set temperature / system prompt with an empty ModelParams()
  • _sync_model_icons(): function_id cached once at __init__ instead of recomputed on every call
  • Streaming "done" status event now emitted correctly (async generator replaces sync generator that could not await)
  • pipes(): response.close() guaranteed in all code paths via finally block
  • Image markdown: invalid URL schemes dropped silently instead of producing broken ![]() tags
  • Payload deep-copy prevents mutation when ENABLE_CACHE_CONTROL is active
  • IndexError on stream chunks with empty choices array
  • Stream error handler caches response body before closing connection

📦 Install / upgrade

Open WebUI Community hub — search OpenRouter Pipe and click Update.

Manual — replace the pipe content in Admin Panel → Functions with the latest openrouter_pipe.py.

From source
```bash
git pull origin main
python test_pipe.py # 431/431 ✓
```

No valve changes required — all new features activate automatically or via existing valves (SYNC_PROVIDER_ICONS to control icon sync, default: enabled).


✅ Compatibility

Requirement Minimum
Open WebUI 0.4.0
Python 3.10
requests 2.20
pydantic 2.0

Full changelog: v1.1.0 → v1.3.0

v1.1.0

15 Feb 09:49

Choose a tag to compare

What's New

Added

  • Password-masked API key - valve settings now use a secure password field (Open WebUI v0.8+)
  • Native dropdown menus - Reasoning Effort, Provider Sort, and Data Collection valves use select widgets instead of free text
  • Event emitter support - __event_emitter__ shows 'Querying OpenRouter...' status in chat UI for non-stream requests
  • Additional defensive keys - metadata, files, tool_ids, session_id, message_id stripped from payload before forwarding to OpenRouter

Tests

  • 23 new unit tests (193 total, 0 failures)
  • New section 16: Valve json_schema_extra validation
  • Event emitter coverage for stream and non-stream paths

Docs

  • README updated: version badge, pipe() signature, internal keys set, test count
  • CHANGELOG formatting fixes (MD022/MD032)

Full Changelog: v1.0.0...v1.1.0