Skip to content

Commit c3764cc

Browse files
committed
address comments
1 parent 1eef32f commit c3764cc

File tree

13 files changed

+72
-80
lines changed

13 files changed

+72
-80
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ venv.bak/
106106
*.backup
107107

108108
# Secrets
109-
secrets.json
109+
secrets.yaml
110110

111111
# Spyder project settings
112112
.spyderproject

eval_protocol/proxy/Dockerfile.gateway

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@ WORKDIR /app
66
# Prevent Python from buffering stdout/stderr
77
ENV PYTHONUNBUFFERED=1
88

9-
# Set secrets path to proxy directory
10-
ENV SECRETS_PATH=/app/proxy_core/secrets.json
11-
129
# Copy requirements file
1310
COPY ./requirements.txt /app/requirements.txt
1411

eval_protocol/proxy/README.md

Lines changed: 32 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ URL paths encode evaluation metadata that gets injected as Langfuse tags:
8080
3. **Retry logic**: Automatic retries with exponential backoff for incomplete traces
8181

8282
### Multi-Project Support
83-
- Store Langfuse credentials for multiple projects in `secrets.json`
83+
- Store Langfuse credentials for multiple projects in `secrets.yaml`
8484
- Route requests to the correct project via `project_id` in URL or use default
8585
- Credentials never exposed to clients
8686

@@ -94,21 +94,17 @@ URL paths encode evaluation metadata that gets injected as Langfuse tags:
9494

9595
1. **Create secrets file:**
9696
```bash
97-
cp proxy_core/secrets.json.example proxy_core/secrets.json
97+
cp proxy_core/secrets.yaml.example proxy_core/secrets.yaml
9898
```
9999

100-
2. **Edit `proxy_core/secrets.json`** with your Langfuse credentials.
101-
**Important**: where we have "my-project", you would use the ID of your Langfuse project, similar to format `cmg00asdf0123...`.
102-
```json
103-
{
104-
"langfuse_keys": {
105-
"my-project": {
106-
"public_key": "pk-lf-...",
107-
"secret_key": "sk-lf-..."
108-
}
109-
},
110-
"default_project_id": "my-project"
111-
}
100+
2. **Edit `proxy_core/secrets.yaml`** with your Langfuse credentials.
101+
**Important**: use your real Langfuse project ID (e.g. `cmg00asdf0123...`).
102+
```yaml
103+
langfuse_keys:
104+
my-project:
105+
public_key: pk-lf-...
106+
secret_key: sk-lf-...
107+
default_project_id: my-project
112108
```
113109
114110
3. **Start services:**
@@ -238,31 +234,27 @@ Forwards any other request to LiteLLM backend with API key injection.
238234
| `REDIS_HOST` | Yes | - | Redis hostname |
239235
| `REDIS_PORT` | No | 6379 | Redis port |
240236
| `REDIS_PASSWORD` | No | - | Redis password |
241-
| `SECRETS_PATH` | No | `proxy_core/secrets.json` | Path to secrets file |
242-
| `REQUEST_TIMEOUT` | No | 300.0 | Request timeout in seconds |
237+
| `SECRETS_PATH` | No | `proxy_core/secrets.yaml` | Path to secrets file (YAML) |
238+
| `LANGFUSE_HOST` | No | `https://cloud.langfuse.com` | Langfuse base URL |
239+
| `REQUEST_TIMEOUT` | No | 300.0 | Request timeout (LLM calls) in seconds |
243240
| `LOG_LEVEL` | No | INFO | Logging level |
244241
| `PORT` | No | 4000 | Gateway port |
245242

246243
### Secrets Configuration
247244

248-
Create `proxy_core/secrets.json`:
249-
```json
250-
{
251-
"langfuse_keys": {
252-
"project-1": {
253-
"public_key": "pk-lf-...",
254-
"secret_key": "sk-lf-..."
255-
},
256-
"project-2": {
257-
"public_key": "pk-lf-...",
258-
"secret_key": "sk-lf-..."
259-
}
260-
},
261-
"default_project_id": "project-1"
262-
}
245+
Create `proxy_core/secrets.yaml`:
246+
```yaml
247+
langfuse_keys:
248+
project-1:
249+
public_key: pk-lf-...
250+
secret_key: sk-lf-...
251+
project-2:
252+
public_key: pk-lf-...
253+
secret_key: sk-lf-...
254+
default_project_id: project-1
263255
```
264256
265-
**Security:** Add `secrets.json` to `.gitignore` (already configured).
257+
**Security:** `secrets.yaml` is ignored via `.gitignore`.
266258

267259
### LiteLLM Configuration
268260

@@ -332,7 +324,7 @@ eval_protocol/proxy/
332324
│ ├── models.py # Pydantic models
333325
│ ├── auth.py # Authentication
334326
│ ├── main.py # Entry point
335-
│ └── secrets.json.example
327+
│ └── secrets.yaml.example
336328
├── docker-compose.yml # Local development stack
337329
├── Dockerfile.gateway # Gateway container
338330
├── config_no_cache.yaml # LiteLLM config
@@ -345,17 +337,17 @@ eval_protocol/proxy/
345337
Extend `AuthProvider` in `auth.py`:
346338
```python
347339
from .auth import AuthProvider
348-
from fastapi import HTTPException
340+
from fastapi import HTTPException, Request
349341
350342
class MyAuthProvider(AuthProvider):
351-
def validate(self, api_key: Optional[str]) -> Optional[str]:
352-
if not api_key or not self.is_valid(api_key):
343+
def validate(self, request: Request) -> Optional[str]:
344+
api_key = None
345+
auth_header = request.headers.get("authorization", "")
346+
if auth_header.startswith("Bearer "):
347+
api_key = auth_header.replace("Bearer ", "").strip()
348+
if not api_key:
353349
raise HTTPException(status_code=401, detail="Invalid API key")
354350
return api_key
355-
356-
def is_valid(self, api_key: str) -> bool:
357-
# Your validation logic
358-
return True
359351
```
360352

361353
Then pass it to `create_app`:

eval_protocol/proxy/docker-compose.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ services:
2222
environment:
2323
- LANGFUSE_PUBLIC_KEY=dummy # Set dummy public and private key so Langfuse instance initializes in LiteLLM, then real keys get sent in proxy
2424
- LANGFUSE_SECRET_KEY=dummy
25-
- LANGFUSE_HOST=https://langfuse.fireworks.ai
2625
volumes:
2726
- ./config_no_cache.yaml:/app/config.yaml:ro
2827
ports:
@@ -48,6 +47,8 @@ services:
4847
- REQUEST_TIMEOUT=300
4948
# Logging level: INFO (default)
5049
- LOG_LEVEL=INFO
50+
# Langfuse and secrets
51+
- SECRETS_PATH=/app/proxy_core/secrets.yaml
5152
ports:
5253
- "4000:4000" # Main public-facing port
5354
networks:

eval_protocol/proxy/proxy_core/app.py

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import os
99
import redis
1010
import logging
11-
import json
11+
import yaml
1212
from pathlib import Path
1313
import sys
1414
from contextlib import asynccontextmanager
@@ -36,33 +36,35 @@ def build_proxy_config() -> ProxyConfig:
3636
if not litellm_url:
3737
raise ValueError("LITELLM_URL environment variable must be set")
3838
request_timeout = float(os.getenv("REQUEST_TIMEOUT", "300.0"))
39+
langfuse_host = os.getenv("LANGFUSE_HOST", "https://cloud.langfuse.com")
3940

40-
# Secrets - use SECRETS_PATH env var if set, otherwise default to proxy/secrets.json
41+
# Secrets - use SECRETS_PATH env var if set, otherwise default to proxy/secrets.yaml
4142
secrets_path_str = os.getenv("SECRETS_PATH")
4243
if secrets_path_str:
4344
secrets_path = Path(secrets_path_str)
4445
else:
45-
secrets_path = Path(__file__).parent / "secrets.json"
46+
secrets_path = Path(__file__).parent / "secrets.yaml"
4647
if not secrets_path.exists():
4748
raise ValueError(
48-
"secrets.json not found! Please create it from secrets.json.example:\n"
49-
" cp litellm_proxy_config/proxy/secrets.json.example litellm_proxy_config/proxy/secrets.json\n"
50-
"Then add your Langfuse API keys to secrets.json"
49+
"Secrets file not found! Please create it from secrets.yaml.example:\n"
50+
" cp eval_protocol/proxy/proxy_core/secrets.yaml.example eval_protocol/proxy/proxy_core/secrets.yaml\n"
51+
"Then add your Langfuse API keys to the secrets file"
5152
)
5253
try:
5354
with open(secrets_path, "r") as f:
54-
secrets_config = json.load(f)
55+
secrets_config = yaml.safe_load(f)
5556
langfuse_keys = secrets_config["langfuse_keys"]
5657
default_project_id = secrets_config["default_project_id"]
57-
logger.info(f"Loaded {len(langfuse_keys)} Langfuse project(s) from secrets.json")
58+
logger.info(f"Loaded {len(langfuse_keys)} Langfuse project(s) from {secrets_path.name}")
5859
except KeyError as e:
59-
raise ValueError(f"Missing required key in secrets.json: {e}")
60-
except json.JSONDecodeError as e:
61-
raise ValueError(f"Invalid JSON in secrets.json: {e}")
60+
raise ValueError(f"Missing required key in secrets file: {e}")
61+
except yaml.YAMLError as e:
62+
raise ValueError(f"Invalid format in secrets file {secrets_path.name}: {e}")
6263

6364
return ProxyConfig(
6465
litellm_url=litellm_url,
6566
request_timeout=request_timeout,
67+
langfuse_host=langfuse_host,
6668
langfuse_keys=langfuse_keys,
6769
default_project_id=default_project_id,
6870
)
@@ -118,12 +120,7 @@ def get_redis(request: Request) -> redis.Redis:
118120
return request.app.state.redis
119121

120122
async def require_auth(request: Request) -> None:
121-
auth_header = request.headers.get("authorization", "")
122-
api_key = None
123-
if auth_header.startswith("Bearer "):
124-
api_key = auth_header.replace("Bearer ", "").strip()
125-
126-
auth_provider.validate(api_key)
123+
auth_provider.validate(request)
127124
return None
128125

129126
# =====================
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
from abc import ABC, abstractmethod
22
from typing import Optional
3+
from fastapi import Request
34

45

56
class AuthProvider(ABC):
67
@abstractmethod
7-
def validate(self, api_key: Optional[str]) -> Optional[str]: ...
8+
def validate(self, request: Request) -> Optional[str]: ...
89

910

1011
class NoAuthProvider(AuthProvider):
11-
def validate(self, api_key: Optional[str]) -> Optional[str]:
12+
def validate(self, request: Request) -> Optional[str]:
1213
return None

eval_protocol/proxy/proxy_core/langfuse.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ async def fetch_langfuse_traces(
210210
langfuse_client = Langfuse(
211211
public_key=config.langfuse_keys[project_id]["public_key"],
212212
secret_key=config.langfuse_keys[project_id]["secret_key"],
213-
host="https://langfuse.fireworks.ai",
213+
host=config.langfuse_host,
214214
)
215215

216216
# Parse datetime strings if provided

eval_protocol/proxy/proxy_core/litellm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ async def handle_chat_completion(
8787
# Add Langfuse configuration
8888
data["langfuse_public_key"] = config.langfuse_keys[project_id]["public_key"]
8989
data["langfuse_secret_key"] = config.langfuse_keys[project_id]["secret_key"]
90-
data["langfuse_host"] = "https://langfuse.fireworks.ai"
90+
data["langfuse_host"] = config.langfuse_host
9191

9292
# Forward to LiteLLM's standard /chat/completions endpoint
9393
# Set longer timeout for LLM API calls (LLMs can be slow)

eval_protocol/proxy/proxy_core/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class ProxyConfig(BaseModel):
1111

1212
litellm_url: str
1313
request_timeout: float = 300.0
14+
langfuse_host: str
1415
langfuse_keys: Dict[str, Dict[str, str]]
1516
default_project_id: str
1617

eval_protocol/proxy/proxy_core/secrets.json.example

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)