Skip to content

Commit a80d056

Browse files
committed
release: v1.10.3 — revert v1.10.2 id rename + refresh module frontmatter
v1.10.2 swapped the function id to 'openrouter-pipe' based on a misread of the portal's slugifier. Re-grounded in OWUI source: src/lib/utils/index.ts -> nameToId(): name.replace(/[^\w]+/g, '_').toLowerCase() (\w = [A-Za-z0-9_], so dashes become underscores) 'OpenRouter Pipe' slugifies to 'openrouter_pipe' — underscores are correct, every existing community pipe under /f/<user>/<slug> uses underscores, and v1.10.2's dash form would have failed portal validation while creating a stranded function row in every existing install's OWUI DB. The real cause of the portal upload error was a stale module-level frontmatter docstring at the top of openrouter_pipe.py — parsed by backend/open_webui/utils/plugin.py:extract_frontmatter against the '^\s*([a-z_]+):\s*(.*)$' pattern. 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 preview surfaced the missing/stale keys as a JavaScript 'undefined' tooltip. Changes ------- function.json id: openrouter-pipe -> openrouter_pipe (reverted) version: 1.10.2 -> 1.10.3 updated_at: 2026-05-31T16:00:00.000Z openrouter_pipe.py Module-level frontmatter docstring rewritten: version: 1.9.0 -> version: 1.10.3 description: refreshed to cover image-gen, video-gen, audio-gen (with their respective embed mechanics), SSRF-guarded media downloads, 99.3% provider-icon coverage, MAX_TOOL_ITERATIONS, encrypted UserValves keys, and the atomic routing-set swap. Unicode arrow '->' was replaced with '..' to avoid non-ASCII edge-cases in the portal's metadata tooltip rendering. Docstring examples in _clean_model_id() and _sync_model_icons() reverted to openrouter_pipe.openai/gpt-4o form. test_pipe.py 5 _function_id simulations + 2 prefix-assertion strings reverted to openrouter_pipe.*. All 939 tests still green. CHANGELOG.md New [1.10.3] section documenting the misdiagnosis, the source evidence for nameToId behaviour, the real frontmatter root cause, and migration steps for any tester who installed v1.10.2. [1.10.2] flagged as superseded — tag kept in git history for traceability only.
1 parent 3d9e1d8 commit a80d056

4 files changed

Lines changed: 30 additions & 21 deletions

File tree

CHANGELOG.md

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
## [1.10.2] — 2026-05-31
10+
## [1.10.3] — 2026-05-31
1111

12-
### Changed
12+
### Fixed
1313

14-
- **Function ID renamed `openrouter_pipe``openrouter-pipe`** (dash, not underscore). The openwebui.com community portal slugifies the listing title (`OpenRouter Pipe``openrouter-pipe`) and rejected the underscored manifest with an "undefined" error on upload. The new ID matches the portal-generated slug, so the published listing now installs cleanly. Internal Python module name (`openrouter_pipe.py`, `import openrouter_pipe`) is unchanged — Python identifiers cannot contain dashes.
14+
- **openwebui.com community portal upload — *undefined* error.** Re-grounded in OWUI source instead of the slug visible in the form. `src/lib/utils/index.ts` defines `nameToId` as `name.replace(/[^\w]+/g, '_').toLowerCase()` (`\w = [A-Za-z0-9_]`), so `OpenRouter Pipe` slugifies to `openrouter_pipe`**underscores are correct, dashes are not**. v1.10.2 had momentarily swapped the id to dashes on a misdiagnosis; this release reverts that change. The real culprit was a stale module-level frontmatter docstring in `openrouter_pipe.py` (parsed by `backend/open_webui/utils/plugin.py:extract_frontmatter` via `^\s*([a-z_]+):\s*(.*)$`): `version: 1.9.0` (last touched at that release) and a description that pre-dated the image/video/audio output flows. When the portal renders the parsed frontmatter alongside the form, missing-or-stale keys surface as a JavaScript `undefined` tooltip on the preview pane.
1515

16-
### Breaking
16+
### Changed
1717

18-
- **Existing Admin-Panel installs that registered under the old `openrouter_pipe` ID are not auto-migrated** — Open WebUI keys functions by ID in its database. After updating, the old function row remains active under the old ID; the new `openrouter-pipe` ID will create a fresh function row when re-installed via the portal. To migrate cleanly: copy your Valves config, uninstall the old function, install the new one, paste the config back. No data loss — chat history is tied to the model selector entry, not the function row.
18+
- **Function ID reverted to `openrouter_pipe`.** Reason: see *Fixed* above — matches the portal's actual slugifier. Reason for the revert specifically: v1.10.2's `openrouter-pipe` would have failed the portal's own validation (every existing community pipe in `/f/<user>/<slug>` uses underscores) and would have created a *new* function row in every existing install's OWUI DB, forcing a manual config copy with no upside. Cleaner to keep the historical id.
19+
- **Module-level frontmatter docstring refreshed**`version: 1.10.3` and a v1.10.x-accurate description (image / video / audio output flows, SSRF-guarded media downloads, 99.3% icon coverage, `MAX_TOOL_ITERATIONS`, encrypted UserValves keys, atomic routing-set swap). Arrow character `` replaced with `..` since the OWUI frontmatter parser keeps the literal value but the portal's frontend renderer occasionally chokes on non-ASCII in metadata tooltips.
1920

2021
### Docs
2122

22-
- Updated docstring references in `_clean_model_id` and `_sync_model_icons` to use the new dash form when illustrating the OWUI manifold prefix (e.g. `openrouter-pipe.openai/gpt-4o`).
23-
- Updated 5 `test_pipe.py` simulations of `_function_id` and the prefix-assertion strings to match the new ID.
23+
- Docstring references in `_clean_model_id` and `_sync_model_icons` reverted to `openrouter_pipe.openai/gpt-4o` form.
24+
- 5 `test_pipe.py` `_function_id` simulations and 2 prefix-assertion strings reverted to `openrouter_pipe.*`. All 939 tests green.
25+
26+
### Breaking note for v1.10.2 testers
27+
28+
If you tagged or installed `1.10.2` between the previous release and this one, your OWUI DB now has a stranded function row under the `openrouter-pipe` id. To clean up: **Admin Panel → Functions** → delete the `openrouter-pipe` entry → install/update `openrouter_pipe` to 1.10.3. Valves config does not migrate automatically — copy it before the delete. No chat history is affected (chat history is keyed on the model selector entry, not the function row).
29+
30+
## [1.10.2] — 2026-05-31 *(superseded by 1.10.3 — do not use)*
31+
32+
Identifier-rename release based on a misread of the OWUI portal slugifier. See 1.10.3 *Fixed* for the corrected root cause. Tag remains in git history for traceability; the published manifest was never accepted by the portal.
2433

2534
## [1.10.1] — 2026-05-31
2635

function.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"id": "openrouter-pipe",
2+
"id": "openrouter_pipe",
33
"name": "OpenRouter Pipe",
44
"type": "manifold",
55
"meta": {
@@ -9,7 +9,7 @@
99
"author": "Sena Labs",
1010
"author_url": "https://github.com/sena-labs",
1111
"funding_url": "https://github.com/sponsors/sena-labs",
12-
"version": "1.10.2",
12+
"version": "1.10.3",
1313
"license": "MIT",
1414
"required_open_webui_version": "0.4.0",
1515
"requirements": ["requests>=2.32.4", "pydantic>=2.0"]
@@ -36,6 +36,6 @@
3636
"content": "openrouter_pipe.py",
3737
"is_active": true,
3838
"is_global": true,
39-
"updated_at": "2026-05-31T15:00:00.000Z",
39+
"updated_at": "2026-05-31T16:00:00.000Z",
4040
"created_at": "2026-01-21T00:00:00.000Z"
4141
}

openrouter_pipe.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
author: Sena Labs
44
author_url: https://github.com/sena-labs
55
funding_url: https://github.com/sponsors/sena-labs
6-
version: 1.9.0
6+
version: 1.10.3
77
license: MIT
88
icon_url: data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9ImJnIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjEwMCUiIHkyPSIxMDAlIj48c3RvcCBvZmZzZXQ9IjAlIiBzdG9wLWNvbG9yPSIjNmQyOGQ5Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjYTc4YmZhIi8+PC9saW5lYXJHcmFkaWVudD48L2RlZnM+PHJlY3Qgd2lkdGg9IjEwMCIgaGVpZ2h0PSIxMDAiIHJ4PSIyMCIgZmlsbD0idXJsKCNiZykiLz48cGF0aCBkPSJNMjAgNTAgQzIwIDMwLCA0MCAzMCwgNTAgMzAgTDUwIDIyIEw2OCA0MCBMNTAgNTggTDUwIDUwIEM0MCA1MCwgMzUgNDUsIDMwIDUwIEMyNSA1NSwgMjAgNzAsIDIwIDUwIFoiIGZpbGw9IndoaXRlIiBvcGFjaXR5PSIwLjk1Ii8+PGNpcmNsZSBjeD0iNzgiIGN5PSIzMCIgcj0iNyIgZmlsbD0id2hpdGUiIG9wYWNpdHk9IjAuOCIvPjxjaXJjbGUgY3g9IjgyIiBjeT0iNTAiIHI9IjciIGZpbGw9IndoaXRlIiBvcGFjaXR5PSIwLjk1Ii8+PGNpcmNsZSBjeD0iNzgiIGN5PSI3MCIgcj0iNyIgZmlsbD0id2hpdGUiIG9wYWNpdHk9IjAuOCIvPjxsaW5lIHgxPSI2OCIgeTE9IjQwIiB4Mj0iNzYiIHkyPSIzMiIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIyIiBvcGFjaXR5PSIwLjUiLz48bGluZSB4MT0iNjgiIHkxPSI0MCIgeDI9Ijc2IiB5Mj0iNTAiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMiIgb3BhY2l0eT0iMC41Ii8+PGxpbmUgeDE9IjY4IiB5MT0iNDAiIHgyPSI3NiIgeTI9IjY4IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiIG9wYWNpdHk9IjAuNSIvPjwvc3ZnPg==
99
required_open_webui_version: 0.4.0
1010
requirements: requests>=2.32.4, pydantic>=2.0
11-
description: The definitive OpenRouter integration for Open WebUI. Full catalog (chat/TTS/audio/image/embeddings), variant routing (:nitro/:exacto/:thinking/:online/:free/:extended), web search plugin with domain filters, server-side category filter, deprecation warnings, extended reasoning (minimal→xhigh + max_tokens + summary), Anthropic interleaved thinking + cache TTL, ZDR enforcement, tool/free-tier filters, provider preferences (only/quantizations/max_price/allow_fallbacks), service tier routing (flex/priority), generation-ID auditability, cached-input cost breakdown, model fallbacks, middle-out compression, citations, auto-discovered provider icons. Per-user API keys and preferences via UserValves, with at-rest key encryption (Fernet, keyed on WEBUI_SECRET_KEY). Native function/tool calling (parallel execution, streaming + non-streaming) with a tool-iteration cap, and an opt-in OpenRouter remaining-credit footer. Transient 429/5xx retries with Retry-After awareness.
11+
description: The definitive OpenRouter integration for Open WebUI. Full catalog (chat, TTS, audio input + generation, image generation, video generation, embeddings) with native OWUI rendering for every output modality. Image-gen models (flux, gemini-image-preview) materialise data: URLs into OWUI files and embed as markdown images. Video-gen models (veo, kling, sora, seedance, hailuo, wan, grok-imagine) route through the async /api/v1/videos endpoint with polling, then re-host the MP4 and embed via block-HTML video. Audio-gen models (lyria, gpt-audio with auto pcm16 -> WAV wrap) stream base64 chunks via /chat/completions modalities=['text','audio'] and embed via block-HTML audio. SSRF-guarded media downloads (openrouter.ai-only whitelist + 100MiB/50MiB byte caps + MIME post-download whitelist). Variant routing (:nitro/:exacto/:thinking/:online/:free/:extended), web search plugin with domain filters, server-side category filter, deprecation warnings, extended reasoning (minimal..xhigh + max_tokens + summary), Anthropic interleaved thinking + cache TTL, ZDR enforcement, tool/free-tier filters, provider preferences (only/quantizations/max_price/allow_fallbacks), service tier routing (flex/priority), generation-ID auditability, cached-input cost breakdown, model fallbacks, middle-out compression, citations (URL-scheme filtered). 55+ hardcoded provider icons plus a 5-layer fallback chain (registry, alias, provider-domain favicon, deterministic letter-SVG) for 99.3% real-brand coverage. Per-user API keys and preferences via UserValves, with at-rest key encryption (Fernet, keyed on WEBUI_SECRET_KEY) and cached decrypt. Native function/tool calling (parallel execution, streaming + non-streaming) with a tool-iteration cap, and an opt-in OpenRouter remaining-credit footer (pre-warmed off the event loop so the SSE stream is never blocked). Transient 429/5xx retries with Retry-After awareness, HTTPAdapter pool sized for concurrent users, atomic routing-set swap so concurrent refreshes never expose an empty model list.
1212
"""
1313

1414
import asyncio
@@ -1368,7 +1368,7 @@ def _clean_model_id(model_id: str) -> str:
13681368
13691369
OpenRouter model IDs use the format ``provider/model`` (e.g.
13701370
``anthropic/claude-3.5-sonnet``). The manifold prefix added by Open
1371-
WebUI is a function id without ``/`` (e.g. ``openrouter-pipe``). We
1371+
WebUI is a function id without ``/`` (e.g. ``openrouter_pipe``). We
13721372
only strip when the text before the first ``.`` contains no ``/`` —
13731373
otherwise the dot is part of the model version (e.g.
13741374
``claude-3.5-sonnet``) and must be preserved.
@@ -1686,7 +1686,7 @@ def _sync_model_icons(self, models: List[dict]) -> None:
16861686
16871687
Open WebUI serves model icons from its database, not from the dicts
16881688
returned by ``pipes()``. OWUI prefixes every pipe model ID with
1689-
``{function_id}.`` (e.g. ``openrouter-pipe.openai/gpt-4o``) and the
1689+
``{function_id}.`` (e.g. ``openrouter_pipe.openai/gpt-4o``) and the
16901690
frontend requests icons using that prefixed ID.
16911691
16921692
Called both on cache miss and on subsequent cache hits (until all

test_pipe.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1927,7 +1927,7 @@ async def _test_pipe_no_msgs_key():
19271927
# (OWUI may overwrite the record after pipes() returns; confirmed on next call)
19281928
_pipe_func = Pipe()
19291929
_pipe_func.valves = Pipe.Valves(OPENROUTER_API_KEY="k", SYNC_PROVIDER_ICONS=True)
1930-
_pipe_func._function_id = "openrouter-pipe" # simulate OWUI module naming
1930+
_pipe_func._function_id = "openrouter_pipe" # simulate OWUI module naming
19311931
_mock_Models_f = MagicMock()
19321932
_mock_Models_f.get_model_by_id.return_value = None # No existing record yet
19331933
_mock_ModelForm_f = MagicMock()
@@ -1947,11 +1947,11 @@ async def _test_pipe_no_msgs_key():
19471947
# Verify DB lookups used prefixed IDs
19481948
_lookup_ids = [c.args[0] for c in _mock_Models_f.get_model_by_id.call_args_list]
19491949
_assert(
1950-
"openrouter-pipe.openai/gpt-4o" in _lookup_ids,
1950+
"openrouter_pipe.openai/gpt-4o" in _lookup_ids,
19511951
"_sync_model_icons: DB lookup uses prefixed ID (openai)",
19521952
)
19531953
_assert(
1954-
"openrouter-pipe.anthropic/claude-3.5-sonnet" in _lookup_ids,
1954+
"openrouter_pipe.anthropic/claude-3.5-sonnet" in _lookup_ids,
19551955
"_sync_model_icons: DB lookup uses prefixed ID (anthropic)",
19561956
)
19571957
# Verify insert_new_model was called (since get_model_by_id returned None)
@@ -1963,11 +1963,11 @@ async def _test_pipe_no_msgs_key():
19631963
_form_calls = _mock_ModelForm_f.call_args_list
19641964
_form_ids = [c.kwargs.get("id", "") for c in _form_calls]
19651965
_assert(
1966-
"openrouter-pipe.openai/gpt-4o" in _form_ids,
1966+
"openrouter_pipe.openai/gpt-4o" in _form_ids,
19671967
"_sync_model_icons: ModelForm uses prefixed ID (openai)",
19681968
)
19691969
_assert(
1970-
"openrouter-pipe.anthropic/claude-3.5-sonnet" in _form_ids,
1970+
"openrouter_pipe.anthropic/claude-3.5-sonnet" in _form_ids,
19711971
"_sync_model_icons: ModelForm uses prefixed ID (anthropic)",
19721972
)
19731973
# After insert (model not yet registered by OWUI), _icons_synced must NOT be updated.
@@ -1982,7 +1982,7 @@ async def _test_pipe_no_msgs_key():
19821982
# 25g. Existing model with user custom icon → skips overwrite
19831983
_pipe_skip = Pipe()
19841984
_pipe_skip.valves = Pipe.Valves(OPENROUTER_API_KEY="k", SYNC_PROVIDER_ICONS=True)
1985-
_pipe_skip._function_id = "openrouter-pipe" # simulate OWUI module naming
1985+
_pipe_skip._function_id = "openrouter_pipe" # simulate OWUI module naming
19861986
_mock_Models_s = MagicMock()
19871987
_existing_model = MagicMock()
19881988
_existing_model.meta.profile_image_url = "https://custom-icon.example.com/icon.png"
@@ -2015,7 +2015,7 @@ async def _test_pipe_no_msgs_key():
20152015
# 25h. Existing model with OWUI default (data: URL) icon → updates with provider icon
20162016
_pipe_update = Pipe()
20172017
_pipe_update.valves = Pipe.Valves(OPENROUTER_API_KEY="k", SYNC_PROVIDER_ICONS=True)
2018-
_pipe_update._function_id = "openrouter-pipe" # simulate OWUI module naming
2018+
_pipe_update._function_id = "openrouter_pipe" # simulate OWUI module naming
20192019
_mock_Models_u = MagicMock()
20202020
_existing_default = MagicMock()
20212021
_existing_default.name = "GPT-4o"

0 commit comments

Comments
 (0)