From 8e36c1c6d8ccdc4c19caeb7971652156ffebb505 Mon Sep 17 00:00:00 2001 From: Nick Date: Thu, 23 Jul 2026 23:25:04 +0300 Subject: [PATCH] docs: make ReliAPI beta claims verifiable --- README.md | 61 ++-- docs/index.html | 859 ++++-------------------------------------------- pyproject.toml | 2 +- 3 files changed, 103 insertions(+), 819 deletions(-) diff --git a/README.md b/README.md index 7732a5c..9e08d1b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # ReliAPI -Reliability layer for API calls: retries, caching, dedup, circuit breakers. +Beta self-hosted proxy for HTTP and LLM calls with Redis-backed caching, +non-streaming LLM idempotency, and configurable LLM budget guardrails. [![npm version](https://badge.fury.io/js/reliapi-sdk.svg)](https://www.npmjs.com/package/reliapi-sdk) [![PyPI version](https://badge.fury.io/py/reliapi-sdk.svg)](https://pypi.org/project/reliapi-sdk/) @@ -8,17 +9,20 @@ Reliability layer for API calls: retries, caching, dedup, circuit breakers. **[Open the project site](https://kikuai-lab.github.io/reliapi/)** +> [!IMPORTANT] +> ReliAPI is beta software for evaluation and self-hosting. It does not provide +> an SLA, managed multi-upstream fallback, exactly-once delivery, quantified +> savings, or published performance targets. + ## Features -- **Retries with Backoff** - Automatic retries with exponential backoff -- **Circuit Breaker** - Prevent cascading failures -- **Caching** - TTL cache for GET requests and LLM responses -- **Idempotency** - Request coalescing with idempotency keys -- **Rate Limiting** - Built-in rate limiting per tier -- **LLM Proxy** - Unified interface for OpenAI, Anthropic, Mistral -- **Cost Control** - Budget caps and cost estimation -- **Self-Service Onboarding** - Automated API key generation -- **Paddle Payments** - Subscription management +- **Caching** - TTL cache for HTTP GET/HEAD and non-streaming LLM responses +- **Idempotency** - Redis-backed primitives used by the non-streaming LLM path +- **LLM Proxy** - Configured OpenAI, Anthropic, and Mistral targets +- **Budget Guardrails** - Pre-request estimates with hard and soft caps +- **Rate Limiting** - Built-in request limits per configured tier +- **Experimental Resilience** - Retry and circuit-breaker code remains under + beta review and is not part of the documented reliability baseline ## Project Structure @@ -50,10 +54,14 @@ Try ReliAPI directly on [RapidAPI](https://rapidapi.com/kikuai-lab-kikuai-lab-de ### Self-Hosting with Docker ```bash -docker run -d -p 8000:8000 \ - -e REDIS_URL="redis://localhost:6379/0" \ - -e RELIAPI_CONFIG_PATH=/app/config.yaml \ - kikudoc/reliapi:latest +git clone https://github.com/KikuAI-Lab/reliapi.git +cd reliapi +cp .env.example .env + +# Add the provider key(s) referenced by config.yaml to .env, then start +# ReliAPI and its Redis service. +docker compose up -d --build +curl http://localhost:8000/healthz ``` ### Local Development @@ -109,8 +117,8 @@ targets: | Endpoint | Method | Description | |----------|--------|-------------| -| `/proxy/http` | POST | Proxy any HTTP API with reliability | -| `/proxy/llm` | POST | Proxy LLM requests with cost control | +| `/v1/proxy/http` | POST | Proxy a request to a configured HTTP target | +| `/v1/proxy/llm` | POST | Proxy a request to a configured LLM target | | `/healthz` | GET | Health check | | `/metrics` | GET | Prometheus metrics | @@ -160,7 +168,7 @@ PADDLE_ENVIRONMENT=sandbox from reliapi_sdk import ReliAPI client = ReliAPI( - base_url="https://reliapi.kikuai.dev", + base_url="http://localhost:8000", api_key="your-api-key" ) @@ -187,7 +195,7 @@ llm_response = client.proxy_llm( import { ReliAPI } from 'reliapi-sdk'; const client = new ReliAPI({ - baseUrl: 'https://reliapi.kikuai.dev', + baseUrl: 'http://localhost:8000', apiKey: 'your-api-key' }); @@ -198,6 +206,20 @@ const response = await client.proxyLlm({ }); ``` +## Beta Limitations + +- Redis must be reachable for shared cache and idempotency behavior. +- HTTP response caching applies to GET and HEAD; LLM caching applies to the + non-streaming path. +- The documented idempotency baseline covers non-streaming LLM calls. HTTP + idempotency and streaming behavior remain under beta review. +- Idempotency is not a promise of exactly-once upstream execution or provider + billing behavior. +- Budget caps use pre-request estimates, not authoritative invoices or + account-wide spending limits. +- Deployment security, target allow-lists, Redis durability, observability, and + provider quotas remain the self-hosting operator's responsibility. + ## Testing ```bash @@ -222,7 +244,8 @@ See [`docs/release.md`](./docs/release.md) and [`docs/SECRETS_SETUP.md`](./docs/ - [OpenAPI Spec](./openapi/openapi.yaml) - [Postman Collection](./postman/collection.json) -- [Live Docs](https://reliapi.kikuai.dev/docs) +- [Project Site](https://kikuai-lab.github.io/reliapi/) +- [Wiki](https://github.com/KikuAI-Lab/reliapi/wiki) ## Support diff --git a/docs/index.html b/docs/index.html index c65cb85..14d10a8 100644 --- a/docs/index.html +++ b/docs/index.html @@ -3,128 +3,20 @@ - ReliAPI - Stability Engine for HTTP and LLM APIs - - - - - - - - - - - + ReliAPI - Beta HTTP and LLM Proxy Primitives + + + + + + + + + + + + + @@ -338,10 +230,6 @@ .vis-content > div > div { min-width: auto !important; } .vis-content .flex.flex-col.items-center { min-width: 60px !important; } .vis-content .flex.flex-col.items-center > div { width: 50px !important; height: 50px !important; font-size: 1.25rem !important; } - .vis-content .server-card { padding: 0.5rem !important; gap: 0.5rem !important; } - .vis-content .server-card svg { width: 24px !important; height: 24px !important; } - .vis-content .server-card .font-medium { font-size: 0.75rem !important; } - .vis-content .server-card .text-sm { font-size: 0.7rem !important; } .vis-content .funnel-box { width: 60px !important; height: 60px !important; padding: 0.5rem !important; } .vis-content .funnel-box svg { width: 32px !important; height: 32px !important; } .vis-content .funnel-box .text-xs { font-size: 0.65rem !important; } @@ -349,8 +237,6 @@ .vis-content .text-2xl { font-size: 1.25rem !important; } .vis-content .text-sm { font-size: 0.75rem !important; } .code-block { font-size: 0.75rem !important; padding: 1rem !important; } - .comparison-table { font-size: 0.875rem; } - .comparison-table th, .comparison-table td { padding: 0.75rem 0.5rem !important; } .link-card { padding: 1rem !important; } .link-icon { width: 40px !important; height: 40px !important; } .btn { padding: 0.75rem 1.5rem !important; font-size: 0.875rem !important; } @@ -380,10 +266,6 @@ .vis-content .flex.flex-col.items-center { min-width: 50px !important; } .vis-content .flex.flex-col.items-center > div { width: 40px !important; height: 40px !important; font-size: 1rem !important; } .vis-content .flex.flex-col.items-center .text-xs { font-size: 0.6rem !important; } - .vis-content .server-card { padding: 0.4rem !important; gap: 0.4rem !important; } - .vis-content .server-card svg { width: 20px !important; height: 20px !important; } - .vis-content .server-card .font-medium { font-size: 0.7rem !important; } - .vis-content .server-card .text-sm { font-size: 0.65rem !important; } .vis-content .funnel-box { width: 50px !important; height: 50px !important; padding: 0.4rem !important; } .vis-content .funnel-box svg { width: 24px !important; height: 24px !important; } .vis-content .funnel-box .text-xs { font-size: 0.6rem !important; } @@ -392,8 +274,6 @@ .vis-content .text-sm { font-size: 0.7rem !important; } .vis-content .flex.flex-col.gap-8 { gap: 0.5rem !important; } .code-block { font-size: 0.7rem !important; padding: 0.75rem !important; } - .comparison-table { font-size: 0.75rem; overflow-x: auto; display: block; } - .comparison-table th, .comparison-table td { padding: 0.5rem 0.25rem !important; white-space: nowrap; } } /* Hero Section */ @@ -705,94 +585,6 @@ padding: 2rem; } - .server-card { - display: flex; - align-items: center; - gap: 1rem; - padding: 1rem; - border-radius: 0.75rem; - border: 2px solid var(--border); - background: var(--card); - transition: all 0.5s ease; - } - - .server-card.error { - border-color: var(--destructive); - background: rgba(248, 113, 113, 0.1); - } - - .server-card.success { - border-color: var(--green); - background: rgba(74, 222, 128, 0.1); - box-shadow: 0 0 30px rgba(74, 222, 128, 0.3); - } - - .server-card.activating { - border-color: var(--primary); - background: rgba(168, 156, 196, 0.1); - } - - .countdown-circle { - width: 192px; - height: 192px; - border-radius: 50%; - border: 4px solid var(--border); - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - position: relative; - transition: all 0.5s ease; - } - - .countdown-circle.warning { - border-color: var(--yellow); - background: rgba(251, 191, 36, 0.1); - } - - .countdown-circle.processing { - border-color: var(--primary); - background: rgba(168, 156, 196, 0.1); - } - - .countdown-circle.success { - border-color: var(--green); - background: rgba(74, 222, 128, 0.1); - box-shadow: 0 0 60px rgba(74, 222, 128, 0.4); - } - - .spinning-ring { - position: absolute; - inset: 0; - border-radius: 50%; - border: 4px solid transparent; - border-top-color: var(--primary); - animation: spin 1s linear infinite; - } - - .retry-box { - width: 64px; - height: 64px; - border-radius: 0.75rem; - border: 2px solid var(--border); - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - background: var(--card); - transition: all 0.3s ease; - } - - .retry-box.active { - border-color: var(--primary); - background: rgba(168, 156, 196, 0.2); - } - - .retry-box.success { - border-color: var(--green); - background: rgba(74, 222, 128, 0.2); - } - .funnel-box { width: 128px; height: 128px; @@ -844,127 +636,6 @@ font-weight: 600; } - /* Statistics Section */ - .stat-card { - padding: 1rem; - border-radius: 0.75rem; - border: 1px solid var(--border); - background: rgba(40, 47, 51, 0.5); - cursor: pointer; - transition: all 0.3s ease; - } - - .stat-card:hover { - border-color: var(--primary); - background: rgba(168, 156, 196, 0.1); - transform: scale(1.05); - box-shadow: 0 0 30px rgba(168, 156, 196, 0.2); - } - - .progress-bar { - height: 12px; - background: var(--card); - border-radius: 9999px; - overflow: hidden; - } - - .progress-fill { - height: 100%; - border-radius: 9999px; - transition: width 1s ease-out; - } - - .progress-fill.red { background: rgba(248, 113, 113, 0.8); } - .progress-fill.green { background: rgba(74, 222, 128, 0.8); } - - .latency-bar { - height: 40px; - background: var(--card); - border-radius: 0.5rem; - overflow: hidden; - cursor: pointer; - transition: all 0.3s ease; - } - - .latency-bar:hover { - transform: scale(1.05); - box-shadow: 0 0 20px rgba(168, 156, 196, 0.3); - } - - .latency-fill { - height: 100%; - border-radius: 0.5rem; - transition: width 1s ease-out; - display: flex; - align-items: center; - padding-left: 0.75rem; - } - - /* Comparison Table */ - .comparison-table { - width: 100%; - border-collapse: collapse; - border-radius: 1rem; - overflow: hidden; - } - - .comparison-table th, - .comparison-table td { - padding: 1.25rem 1rem; - text-align: center; - } - - .comparison-table th { - background: transparent; - border-bottom: 1px solid var(--border); - font-weight: 500; - color: var(--muted-foreground); - } - - .comparison-table th.highlight { - color: var(--primary); - font-weight: 700; - font-size: 1.125rem; - } - - .comparison-table tbody tr { - border-bottom: 1px solid rgba(58, 66, 72, 0.5); - transition: all 0.3s ease; - } - - .comparison-table tbody tr:hover { - background: rgba(168, 156, 196, 0.05); - } - - .comparison-table td:first-child { - text-align: left; - padding-left: 1.5rem; - } - - .status-icon { - width: 32px; - height: 32px; - border-radius: 50%; - display: inline-flex; - align-items: center; - justify-content: center; - } - - .status-icon.full { - background: rgba(74, 222, 128, 0.2); - color: var(--green); - } - - .status-icon.partial { - background: rgba(251, 191, 36, 0.2); - color: var(--yellow); - } - - .status-icon.none { - background: rgba(248, 113, 113, 0.2); - color: var(--destructive); - } - /* Code Examples */ .code-tabs { display: flex; @@ -1160,9 +831,10 @@ +

Beta ยท Self-hosted

ReliAPI

-

Stability Engine for HTTP and LLM APIs

+

Caching, non-streaming LLM idempotency, and budget guardrails

@@ -1174,12 +846,6 @@

ReliAPI

Documentation
- -
- - ReliAPI - Stop losing money on failed OpenAI and Anthropic API calls. | Product Hunt - -
@@ -1188,20 +854,15 @@

ReliAPI

- +
-

- Transform - Chaos - into - Stability -

+

Self-hosted Proxy Primitives for Evaluation

-
Chaos
+
Requests
@@ -1261,7 +922,7 @@

-
Stability
+
Responses
@@ -1274,31 +935,16 @@

See ReliAPI in Action

-

Click a scenario to see how it works

+

Click a scenario to see an illustrative beta flow

+

These flows cover the documented non-streaming LLM and budget baseline; review the Beta Limitations before integrating.

-
- - - - +
Budget Cap Hit
-
Cost protection
+
Pre-request estimate
@@ -1324,193 +970,6 @@

See ReliAPI in Action

- -
-
-

Performance That Speaks for Itself

-

Hover over metrics to explore the ReliAPI difference

-

*Benchmarks are synthetic. Actual results depend on environment. See methodology

- -
- -
-

Direct API vs With ReliAPI

-
-
-
- Error Rate - -
-
-
-
Direct
-
-
20%
-
-
-
-
ReliAPI
-
-
1%
-
-
-
- -
-
- Cost Variance - -
-
-
-
Direct
-
-
ยฑ30%
-
-
-
-
ReliAPI
-
-
ยฑ2%
-
-
-
- -
-
- Cache Hit Rate - -
-
-
-
Direct
-
-
15%
-
-
-
-
ReliAPI
-
-
68%
-
-
-
-
-
- - -
-

P95 Proxy Overhead (ms)

-

Additional latency added by proxy layer

-
-
-
- Helicone - ~40ms -
-
-
-
-
-
-
- LiteLLM - ~30ms -
-
-
-
-
-
-
- Portkey - ~25ms -
-
-
-
-
-
-
- ReliAPI - ~15ms -
-
-
-
-
-
-
-
-
-
- - -
-
-

How We Compare

-

Feature comparison with popular alternatives

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FeatureReliAPILiteLLMPortkeyHelicone
Self-hosted Optionโœ“โœ“โœ“โœ—
HTTP + LLM Supportโœ“โœ—โœ—โœ—
Idempotency Keysโœ“โœ—~โœ—
Budget Capsโœ“~โœ“~
Minimal Configโœ“~~โœ“
Streaming Supportโœ“โœ“โœ“โœ“
-
-
-
-
@@ -1547,7 +1006,7 @@

Get Started Today

- +
@@ -1557,7 +1016,7 @@

Get Started Today

- +
@@ -1571,16 +1030,9 @@

Get Started Today

- -
- - ReliAPI - Stop losing money on failed OpenAI and Anthropic API calls. | Product Hunt - -
-
@@ -1630,166 +1082,6 @@

Get Started Today

let animationTimeout = null; const scenarios = { - 'provider-errors': { - chaos: ` -
-
-
-
- ๐Ÿ“จ -
- Your Request -
-
โ†’
-
-
- -
-
Primary Server
-
โŒ Error 500!
-
-
-
- -
-
Backup Server
-
Standby
-
-
-
-
โ†’
-
-
- โ“ -
- Response -
-
-
- `, - processing: ` -
-
-
-
- ๐Ÿ“จ -
- Your Request -
-
โ†’
-
-
- -
-
Primary Server
-
Offline
-
-
-
- -
-
Backup Server
-
๐Ÿ”„ Activating...
-
-
-
-
โ†’
-
-
- โ“ -
- Response -
-
-
- `, - resolved: ` -
-
-
-
- ๐Ÿ“จ -
- Your Request -
-
โ†’
-
-
- -
-
Primary Server
-
Offline
-
-
-
- -
-
Backup Server
-
โœ… Online!
-
- -
-
-
โ†’
-
-
- โœ… -
- Response -
-
-
- ` - }, - 'rate-limits': { - chaos: ` -
-
-
- -
429
-
Rate Limited!
-
-
-
Retry 1
-
Retry 2
-
Retry 3
-
-
-
- `, - processing: ` -
-
-
-
-
3
-
Retry #2
-
-
-
Retry 1
-
Retry 2
-
Retry 3
-
-
-
- `, - resolved: ` -
-
-
- -
Success!
-
-
-
Retry 1
-
Retry 2
-
Done
-
-
-
- ` - }, 'request-storm': { chaos: `
@@ -1801,8 +1093,8 @@

Get Started Today

`).join('')}
-
8
-
requests
+
N
+
same-key calls
โ†’
@@ -1825,8 +1117,8 @@

Get Started Today

-
8
-
requests
+
N
+
same-key calls
โ†’
@@ -1849,8 +1141,8 @@

Get Started Today

-
8
-
requests
+
N
+
same-key calls
โ†’
@@ -1863,7 +1155,7 @@

Get Started Today

1
- request + upstream owner
@@ -1876,17 +1168,17 @@

Get Started Today

-
$150.00
-
Current spending
+
Estimate
+
Above configured cap
-
Budget: $100
+
Hard cap
-
โš ๏ธ Budget exceeded by $50!
+
โš ๏ธ Estimate exceeds the hard cap
`, @@ -1896,17 +1188,17 @@

Get Started Today

-
Analyzing...
-
Applying budget protection
+
Evaluating...
+
Applying configured policy
-
Budget: $100
+
Configured cap
-
๐Ÿ›ก๏ธ ReliAPI protecting your budget...
+
Checking the estimate before the provider call...
`, @@ -1916,17 +1208,17 @@

Get Started Today

-
$99.50
-
Budget protected!
+
Rejected
+
Provider call not started
-
Budget: $100 โœ“
+
Hard cap โœ“
-
โœ… Saved $50.50 by caching & deduplication!
+
Hard-cap rejection is returned in response metadata
` @@ -1967,7 +1259,7 @@

Get Started Today

visualization.className = 'visualization-area processing'; visContent.innerHTML = scenarios[scenario].processing; phaseBadge.className = 'phase-badge processing'; - phaseBadge.innerHTML = ' ReliAPI handling it'; + phaseBadge.innerHTML = ' Illustrative flow'; }, 2000); // Resolved phase @@ -1975,7 +1267,7 @@

Get Started Today

visualization.className = 'visualization-area resolved'; visContent.innerHTML = scenarios[scenario].resolved; phaseBadge.className = 'phase-badge resolved'; - phaseBadge.innerHTML = ' Problem solved'; + phaseBadge.innerHTML = ' Illustration complete'; }, 4000); } @@ -1983,15 +1275,14 @@

Get Started Today

btn.addEventListener('click', () => runScenario(btn.dataset.scenario)); }); - // Auto-activate Provider Errors when section comes into view + // Auto-activate the LLM idempotency example when the section comes into view const featuresSection = document.querySelector('.section.section-bg'); const featuresObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting && !activeScenario) { - // Auto-activate Provider Errors scenario - const providerErrorsBtn = document.querySelector('[data-scenario="provider-errors"]'); - if (providerErrorsBtn) { - runScenario('provider-errors'); + const idempotencyBtn = document.querySelector('[data-scenario="request-storm"]'); + if (idempotencyBtn) { + runScenario('request-storm'); } // Unobserve after activation featuresObserver.unobserve(entry.target); @@ -2003,55 +1294,25 @@

Get Started Today

featuresObserver.observe(featuresSection); } - // Animate stats on scroll - const statsObserver = new IntersectionObserver((entries) => { - entries.forEach(entry => { - if (entry.isIntersecting) { - document.getElementById('stat-error-direct').style.width = '20%'; - document.getElementById('stat-error-reli').style.width = '1%'; - document.getElementById('stat-cost-direct').style.width = '30%'; - document.getElementById('stat-cost-reli').style.width = '2%'; - document.getElementById('stat-cache-direct').style.width = '15%'; - document.getElementById('stat-cache-reli').style.width = '68%'; - - setTimeout(() => { - document.getElementById('latency-helicone').style.width = '100%'; - }, 500); - setTimeout(() => { - document.getElementById('latency-litellm').style.width = '75%'; - }, 650); - setTimeout(() => { - document.getElementById('latency-portkey').style.width = '62%'; - }, 800); - setTimeout(() => { - document.getElementById('latency-reliapi').style.width = '37%'; - }, 950); - } - }); - }, { threshold: 0.2 }); - - document.querySelectorAll('.stat-card').forEach(card => statsObserver.observe(card)); - document.querySelectorAll('.latency-bar').forEach(bar => statsObserver.observe(bar)); - // Code Examples const codeExamples = { python: `import requests response = requests.post( - "https://reliapi.kikuai.dev/proxy/llm", + "http://localhost:8000/v1/proxy/llm", headers={ "X-API-Key": "YOUR_API_KEY", "X-Idempotency-Key": "unique-request-id" }, json={ "target": "openai", - "model": "gpt-4", + "model": "gpt-4o-mini", "messages": [{"role": "user", "content": "Hello!"}] } ) print(response.json())`, - javascript: `const response = await fetch("https://reliapi.kikuai.dev/proxy/llm", { + javascript: `const response = await fetch("http://localhost:8000/v1/proxy/llm", { method: "POST", headers: { "X-API-Key": "YOUR_API_KEY", @@ -2060,20 +1321,20 @@

Get Started Today

}, body: JSON.stringify({ target: "openai", - model: "gpt-4", + model: "gpt-4o-mini", messages: [{ role: "user", content: "Hello!" }] }) }); const data = await response.json(); console.log(data);`, - curl: `curl -X POST https://reliapi.kikuai.dev/proxy/llm \\ + curl: `curl -X POST http://localhost:8000/v1/proxy/llm \\ -H "X-API-Key: YOUR_API_KEY" \\ -H "X-Idempotency-Key: unique-request-id" \\ -H "Content-Type: application/json" \\ -d '{ "target": "openai", - "model": "gpt-4", + "model": "gpt-4o-mini", "messages": [{"role": "user", "content": "Hello!"}] }'` }; diff --git a/pyproject.toml b/pyproject.toml index 9c07bb0..dde2f9d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,7 @@ dev = [ [project.urls] "Homepage" = "https://github.com/KikuAI-Lab/reliapi" -"Documentation" = "https://reliapi.kikuai.dev" +"Documentation" = "https://kikuai-lab.github.io/reliapi/" "Bug Tracker" = "https://github.com/KikuAI-Lab/reliapi/issues" [tool.setuptools.packages.find]