Add Gemini provider + custom model support + custom endpoint - #3
Add Gemini provider + custom model support + custom endpoint#3olegbrok wants to merge 3 commits into
Conversation
1. Sanitizer bypass: Add multi-pass checking to defeat #define macro evasion. Blocked function names are now caught even when aliased via preprocessor macros, token pasting (##), or multi-line defines. 2. Rate limiter: Switch from in-memory to Redis-backed storage so limits are enforced globally across Gunicorn workers instead of per-worker. Add Redis service to docker-compose.yml. 3. Path leaks: Scrub internal paths (/tmp/daisy-build-*, /opt/daisy/*) from stderr before returning compilation errors to users. Also: - Add security headers (X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, Referrer-Policy) to Caddyfile - Pin DaisySP to specific commit hash for reproducible builds Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…upport - Gemini provider: gemini-2.5-pro, gemini-2.0-flash, gemini-1.5-pro with streaming via generateContent SSE endpoint and systemInstruction mapping - Custom Endpoint provider: OpenAI-compatible base URL + key + model config with streaming support for any Chat Completions API - Per-provider custom model ID: input field in settings, persisted to localStorage, appears as "Custom: <id>" at top of model dropdown - Updated settings modal with Gemini key field and custom endpoint config (base URL, API key, model ID) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
bradbrok
left a comment
There was a problem hiding this comment.
Review: Not quite ready to merge
The feature work is solid and follows existing patterns well. The security fixes are good. But there are a few things to address before merging.
Must fix
1. Mixed concerns — split into two PRs
Commit 1 (0a403cb) is server security fixes (sanitizer, rate limiter, path scrubbing, security headers, pinned DaisySP). Commits 2-3 are frontend feature work (Gemini, custom endpoint, model updates). These are completely unrelated and should be separate PRs. The security fixes should merge immediately without waiting on feature review.
2. Dead code: setCustomModel is imported but never used
setCustomModel is exported from providers.js and imported in app.js, but there's no UI input field to actually set a per-provider custom model for non-custom providers. getCustomModel() is wired into the dropdown rendering, so if someone manually sets localStorage, it would show up — but there's no way for users to do this through the UI. Either:
- Add the input field to the settings modal (per-provider "Custom model ID" text input)
- Or remove the dead code and add it in a follow-up when the UI is ready
3. localStorage key naming collision risk
daisy-gpt-custom-model→ custom endpoint's model ID (getCustomEndpointModel)daisy-gpt-custom-model-custom→ per-provider custom model for the "custom" provider (getCustomModel('custom'))
These are different keys with overlapping semantics. If someone sets both, the behavior would be confusing. Suggest renaming the endpoint one to daisy-gpt-custom-endpoint-model to make the distinction clear.
Nits (non-blocking)
4. Gemini API key in URL query param — This is how Google documents the REST API, so it's not wrong, but keys in URLs end up in browser history and server access logs. The x-goog-api-key header is a supported alternative worth considering.
5. DaisySP full clone — Removing --depth 1 to checkout a specific commit means cloning full history. Could use git fetch origin <hash> --depth 1 + git checkout FETCH_HEAD for faster builds.
6. X-XSS-Protection header — Deprecated and removed from modern browsers (Chrome 78+). Doesn't hurt to have it, but Content-Security-Policy would be the modern replacement.
What looks good
- Gemini provider correctly maps
assistant→model, usessystemInstruction, and handles both streaming (streamGenerateContent?alt=sse) and sync (generateContent) endpoints - Custom endpoint follows OpenAI-compatible Chat Completions format — works with LiteLLM, vLLM, LM Studio, etc.
- Sanitizer multi-pass approach is solid — handles
#definebody checks, multi-line continuations, and token pasting - Redis-backed rate limiting fixes the per-worker isolation bug
- Path scrubbing in
compiler.pyis clean
What's in this PR
1. Google Gemini Provider
gemini-2.5-pro,gemini-2.0-flash,gemini-1.5-prostreamGenerateContent?alt=ssesystemInstructionassistantrole mapped tomodelfor Gemini's content format2. Custom Model ID (per-provider)
Custom: <id>3. Custom Endpoint Provider
POST {baseUrl}/chat/completions)Files changed:
providers.js,app.js,index.html