Skip to content

Reconciled survivors from PR #5: /v1beta surface, SSRF guard, truncation recovery, script restore - #6

Merged
luuquangvu merged 5 commits into
luuquangvu:mainfrom
kahlos:survivors-pr
Aug 15, 2026
Merged

Reconciled survivors from PR #5: /v1beta surface, SSRF guard, truncation recovery, script restore#6
luuquangvu merged 5 commits into
luuquangvu:mainfrom
kahlos:survivors-pr

Conversation

@kahlos

@kahlos kahlos commented Aug 14, 2026

Copy link
Copy Markdown

Follow-up to the review on #5 — we've reconciled the fork integration with your comments (details below) and this PR carries only the items that were not objected to.

What changed vs your main

  1. Native Gemini /v1beta REST surface (app/server/gemini.py, app/models/gemini_models.py, app/server/middleware.py::verify_gemini_api_key, app/main.py wiring): GET /v1beta/models, GET /v1beta/models/{model}, POST ...:generateContent, ...:streamGenerateContent, x-goog-api-key auth, Google-style error envelopes. Independent of model discovery — resolves against your dynamic AvailableModel registry via _resolve_model_name.
  2. SSRF guard (app/utils/helper.py::reject_unsafe_url + allow_private_url_fetch / url_fetch_timeout config): blocks private/loopback targets for server-side URL image fetches; DNS-rebind TOCTOU documented. Left as an opt-out knob.
  3. Truncated-stream recovery (app/services/client.py::fetch_last_model_turn + app/server/chat.py::_recover_stream_output): when a stream dies mid-response, Gemini finalizes the turn server-side; this polls LIST_CONVERSATION_TURNS for the completed turn (new rcid) and streams the missing tail. Different scope from timeout/keepalive: it recovers content after a dead connection, not the connection itself. Gated by recovery_timeout (default 60s, 0 disables).
  4. Bug fix: app/server/chat.py _resolve_model_name called client.resolve_model(...), which does not exist on the wrapper or the library — the library exposes _resolve_model_by_name (same ValueError contract). Renamed.
  5. scripts/start-gemini-api.sh restored — deleted in 71c0db2 with no replacement in scripts/USAGE.md; used for local start/stop/status.
  6. app/services/pool.py: _init_one/_init_attempt extraction (behavior-preserving).

Reconciliation with your review (PR #5)

Your point Resolution
LMDB size Defaults back to 256 MB / 14 d; storage.max_size remains the customization knob
Timeout/keepalive Agreed — the pinned lib already handles it (socket-stall wait_for, watchdog, refresh); C4 dropped
Compaction gate Agreed — our gate missed large <8-turn inputs (early return at len <= 8); your attachment fallback covers the case; dropped
config.yaml Not in this PR — upstream keeps config/config.yaml; our fork's gitignored real-credentials posture stays local
Runtime model discovery Superseded by your dynamic AvailableModel; dropped
validate_session_on_init Dropped; lib account-status covers client health

We have integrated 71c0db2 + c8e0a83 into our fork and validated it live (/health, /v1/models, chat stream/non-stream, /v1beta generateContent all 200; pyright 0/0/0, ruff baseline).

kahlos added 3 commits August 14, 2026 12:53
…, SSRF guard, truncation recovery, model-resolution fix, start script

vs luuquangvu/main:
- app/server/gemini.py + app/models/gemini_models.py + app/models/__init__.py + app/main.py + app/server/middleware.py: native Gemini /v1beta REST surface (models, generateContent, streamGenerateContent, x-goog-api-key auth, Google error envelopes) - unobjected in review
- app/utils/helper.py + app/utils/config.py + config/config.yaml: SSRF guard (reject_unsafe_url, allow_private_url_fetch, url_fetch_timeout); recovery_timeout knob
- app/services/client.py + app/server/chat.py: truncated-stream recovery via LIST_CONVERSATION_TURNS polling; fix chat.py:688 calling nonexistent client.resolve_model (lib: _resolve_model_by_name)
- scripts/start-gemini-api.sh: restore local start/stop helper (deleted in 71c0db2 with no replacement)
- app/services/pool.py: extract _init_one/_init_attempt (behavior-preserving)
Ruff E402/SIM105 in app/main.py (self-introduced by the survivors main.py
edit): the mimetypes loop ran before module imports and used try/except-pass.
Imports first, loop after (still at import time, before any upload), no noqa
needed. All 4 CI steps now pass: ruff check, ruff format, ty, pyright.
kahlos added a commit to kahlos/Gemini-FastAPI that referenced this pull request Aug 14, 2026
Mirrors survivors-pr b1ed8ba (PR luuquangvu#6): the mimetypes loop ran before module
imports (E402 x6) with try/except-pass (SIM105) - self-introduced by the C1
survivors main.py edit, mislabeled 'pre-existing' in LOGBOOK. Imports first,
loop after (still at import time, before any upload). Local line now matches
PR luuquangvu#6 exactly: ruff check/format, ty, pyright all pass.
kahlos added a commit to kahlos/Gemini-FastAPI that referenced this pull request Aug 14, 2026
The 9fa9059 merge dropped the VideoGeneration branch from the tool
categorization loop, silently discarding video_generation tools, and left
build_video_generation_instruction (helper.py:834) without callers (PR luuquangvu#6
pruned it upstream as dead - correct on that surface). Restore: import,
video_tools list + isinstance/dict branches, instruction nudge next to the
image one (chat.py:2710). Live probe: 200, model replies with its known
placeholder refusal - async server-side video completion on this account;
URL retrieval from LIST_CONVERSATION_TURNS remains open (piece 2).
@luuquangvu luuquangvu self-assigned this Aug 14, 2026
- removing _recover_stream_output, as it’s now handled upstream.
- removing fetch_last_model_turn since it’s already included upstream.
- eliminating the unnecessary looks_like_html function.
@luuquangvu
luuquangvu merged commit 85d7a89 into luuquangvu:main Aug 15, 2026
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