Skip to content

Commit e20267a

Browse files
committed
feat: release v1.2.0 — session pooling, model caching, backoff, safety guards
- Connection pooling via requests.Session - Model list caching with 5-min TTL and valve fingerprint - Exponential backoff with jitter on transient errors - Citation URL sanitization and base URL validation - Error/empty-messages guards, fallback deduplication - deepcopy payload, response.close() in finally blocks - Specific HTTP error messages (429/402/401/403) - Removed pre-flight /auth/key check (single round-trip) - Updated tests (195/195), docs, and metadata
1 parent 0e37dbc commit e20267a

10 files changed

Lines changed: 567 additions & 347 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,6 @@ htmlcov/
3737

3838
# Logs
3939
*.log
40+
41+
tmpclaude-*
42+
nul

CHANGELOG.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,61 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.2.0] - 2026-02-17
9+
10+
### Added
11+
12+
- **Connection pooling** via `requests.Session` for better performance across multiple API calls
13+
- **Model list caching** with 5-minute TTL and valve-fingerprint invalidation — avoids redundant API calls when reopening the model selector
14+
- **Exponential backoff with jitter** on transient errors (Timeout, ConnectionError) — `min(2^attempt + random, 30s)`
15+
- **Fallback deduplication** — duplicate models in `FALLBACK_MODELS` are silently removed
16+
- **Citation URL sanitization** — non-HTTP URLs are filtered out; parentheses in URLs are percent-encoded
17+
- **Base URL validation**`OPENROUTER_BASE_URL` must start with `https://` or `http://` (Pydantic field_validator)
18+
- **"error" model guard** — selecting the error pseudo-model returns an actionable message instead of hitting the API
19+
- **Empty messages guard** — returns a clear error if the message list is empty
20+
- **Fallback model attribution** — non-stream responses show "Responded by: model-id" when a fallback model handled the request
21+
- **HTTP 502 auth detection** — Clerk 502 errors (malformed API key) are now caught at model-list time
22+
23+
### Changed
24+
25+
- Minimum requirements bumped: `requests>=2.20`, `pydantic>=2.0`
26+
- Error prefix changed from "OpenRouter Pipe Error" to "OpenRouter Error" for cleaner UX
27+
- HTTP error messages now include specific guidance per status code (429=rate limit, 402=credits, 401=key, 403=access)
28+
- Empty API response returns an informative message instead of an empty string
29+
- Timeout error messages now show the configured timeout value and suggest increasing it
30+
- Improved all valve descriptions for clarity and actionability
31+
- Pre-flight `/auth/key` check removed — auth errors are now detected directly from the `/models` response (eliminates one HTTP round-trip)
32+
- `_prepare_payload` uses `copy.deepcopy` instead of shallow `body.copy()` to prevent mutation of nested structures
33+
- `_build_headers` uses cached env vars (`WEBUI_URL`, `WEBUI_NAME`) instead of calling `os.getenv()` on every request
34+
- `FREE_ONLY` pricing comparison uses `float()` instead of string comparison
35+
- Model cache key includes `MODEL_PREFIX` to prevent stale results after prefix changes
36+
- Removed unused `_API_PATH_AUTH` constant and `auth_url` property
37+
38+
### Fixed
39+
40+
- Fixed potential payload mutation when `ENABLE_CACHE_CONTROL` is active (deepcopy prevents side effects)
41+
- Fixed potential `IndexError` on stream chunks with empty `choices` array
42+
- Fixed stream error handler not caching response body before closing connection
43+
- Safe `isinstance(err, dict)` checks before calling `.get()` on error objects
44+
- `_close_think_tag()` helper eliminates duplicated think-tag closure logic (was 5x repeated)
45+
- `_stream_response` now closes the response in a `finally` block even on consumer `break`
46+
47+
## [1.1.1] - 2026-02-17
48+
49+
### Changed
50+
51+
- Pre-compiled citation regex at module level for better performance
52+
- Added docstrings to all public and internal methods (`pipe`, `_prepare_payload`, `_stream_response`, `_non_stream_response`, `_retryable_request`, `_build_headers`)
53+
- Translated TESTING.md to English for international audience
54+
55+
### Fixed
56+
57+
- Test suite now runs on Windows without requiring `PYTHONUTF8=1` (UTF-8 stdout wrapper)
58+
- Fixed stale test count in CONTRIBUTING.md and TESTING.md (170 → 193)
59+
- Fixed typo in TESTING.md pre-release checklist
60+
- Updated SECURITY.md to list v1.1.x as supported
61+
- Updated `function.json` metadata date
62+
863
## [1.1.0] - 2026-02-15
964

1065
### Added

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ python test_pipe.py
2323
### Running Tests
2424

2525
```bash
26-
python test_pipe.py # Unit tests (170 tests)
26+
python test_pipe.py # Unit tests (195 tests)
2727
python integration_test.py # Live API tests (requires OPENROUTER_API_KEY)
2828
```
2929

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<img src="https://capsule-render.vercel.app/api?type=waving&color=0:0d1117,50:1a1b2e,100:2d1b69&height=180&section=header&text=OpenRouter%20Pipe&fontColor=a78bfa&fontSize=42&animation=fadeIn&fontAlignY=36&desc=Open%20WebUI%20%E2%86%94%20OpenRouter%20Integration&descAlignY=56&descColor=8b5cf6" width="100%"/>
44

5-
<a href="https://github.com/sena-labs/OpenRouter-Pipe"><img src="https://img.shields.io/badge/version-1.1.0-0d1117?style=for-the-badge&labelColor=7c3aed&color=0d1117" alt="version"></a>&nbsp;
5+
<a href="https://github.com/sena-labs/OpenRouter-Pipe"><img src="https://img.shields.io/badge/version-1.2.0-0d1117?style=for-the-badge&labelColor=7c3aed&color=0d1117" alt="version"></a>&nbsp;
66
<a href="https://www.python.org/"><img src="https://img.shields.io/badge/python-≥3.10-0d1117?style=for-the-badge&logo=python&logoColor=white&labelColor=3776AB" alt="python"></a>&nbsp;
77
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-0d1117?style=for-the-badge&labelColor=blue" alt="license"></a>&nbsp;
88
<a href="https://docs.openwebui.com"><img src="https://img.shields.io/badge/Open%20WebUI-compatible-0d1117?style=for-the-badge&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiPjxwYXRoIGQ9Ik0xMiAyQzYuNDggMiAyIDYuNDggMiAxMnM0LjQ4IDEwIDEwIDEwIDEwLTQuNDggMTAtMTBTMTcuNTIgMiAxMiAyem0wIDE4Yy00LjQyIDAtOC0zLjU4LTgtOHMzLjU4LTggOC04IDggMy41OCA4IDgtMy41OCA0LTggOHoiLz48L3N2Zz4=&logoColor=white&labelColor=1a1a2e" alt="openwebui"></a>
@@ -26,7 +26,7 @@ Provider routing · Reasoning tokens · Streaming · Fallbacks · Cache control
2626
OpenRouter Pipe is the most feature-complete integration between [Open WebUI](https://docs.openwebui.com) and [OpenRouter](https://openrouter.ai). It gives you access to **300+ AI models** — including GPT-5, Claude 4, Gemini 2.5, Llama 4, DeepSeek R1, and more — directly in your Open WebUI interface, with zero configuration beyond an API key.
2727

2828
**Key differentiators:**
29-
- **Pre-flight API key validation** — invalid keys are caught before you see any models, not after you send a message
29+
- **Pre-flight API key validation** — invalid keys are caught at model-fetch time, not after you send a message
3030
- **Full provider routing** — sort, prefer, exclude, and require parameters across providers
3131
- **Native reasoning tokens**`<think>` blocks with configurable effort levels
3232
- **Production-grade reliability** — retry logic, fallback models, mid-stream error recovery
@@ -173,7 +173,7 @@ It also removes `user` when sent as a dict (OWUI format) since OpenRouter expect
173173
|-----------|----------|
174174
| Open WebUI | v0.4.0+ |
175175
| Python | 3.10, 3.11, 3.12, 3.13 |
176-
| Pydantic | v1.x and v2.x |
176+
| Pydantic | v2.x (v2.0+) |
177177
| OpenRouter API | v1 |
178178

179179
---
@@ -184,7 +184,7 @@ It also removes `user` when sent as a dict (OWUI format) since OpenRouter expect
184184
OpenRouter-Pipe/
185185
├── openrouter_pipe.py # Main pipe source (install this in Open WebUI)
186186
├── function.json # Open WebUI community manifest (metadata, tags, categories)
187-
├── test_pipe.py # Unit test suite (193 tests)
187+
├── test_pipe.py # Unit test suite (195 tests)
188188
├── integration_test.py # Live API integration tests (47 tests)
189189
├── TESTING.md # Pre-release testing checklist
190190
├── SECURITY.md # Security policy and vulnerability reporting

SECURITY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
## Supported Versions
44

55
| Version | Supported |
6-
|---------|-----------|
6+
|---------|-----------|| 1.2.x | Yes || 1.1.x | Yes |
77
| 1.0.x | Yes |
88
| < 1.0 | No |
99

0 commit comments

Comments
 (0)