Skip to content

Add Gemini provider + custom model support + custom endpoint - #3

Open
olegbrok wants to merge 3 commits into
bradbrok:mainfrom
olegbrok:feature/gemini-and-custom-models
Open

Add Gemini provider + custom model support + custom endpoint#3
olegbrok wants to merge 3 commits into
bradbrok:mainfrom
olegbrok:feature/gemini-and-custom-models

Conversation

@olegbrok

Copy link
Copy Markdown

What's in this PR

1. Google Gemini Provider

  • Models: gemini-2.5-pro, gemini-2.0-flash, gemini-1.5-pro
  • Streaming via streamGenerateContent?alt=sse
  • System prompt mapped to systemInstruction
  • assistant role mapped to model for Gemini's content format
  • API key field + Test button in settings UI

2. Custom Model ID (per-provider)

  • Any provider can now have a custom model ID typed in
  • Appears at top of model dropdown as Custom: <id>
  • Persisted to localStorage per provider
  • Useful for new model releases before the list is updated

3. Custom Endpoint Provider

  • OpenAI-compatible Chat Completions format (POST {baseUrl}/chat/completions)
  • Fields: Base URL, API key (optional, for local servers), model ID
  • Works with LiteLLM, LM Studio, vLLM, Ollama (alternative to built-in), etc.
  • Streaming supported

Files changed: providers.js, app.js, index.html

olegbrok and others added 3 commits March 14, 2026 09:04
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 bradbrok left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 assistantmodel, uses systemInstruction, 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 #define body checks, multi-line continuations, and token pasting
  • Redis-backed rate limiting fixes the per-worker isolation bug
  • Path scrubbing in compiler.py is clean

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants