docs: README updates for gemini, stealth coherence, headed mode

Reflect the previously-deferred items as done: gemini provider is fully wired
to native generateContent (vision + audio), unit-tested, with a note that live
use needs a real Google key. Document that get_stealth_script now takes
os/browser/locale/seed and returns a fingerprint, and that the evasion script
is templated to match it (coherent) — inject both together or share a seed.
Note reasoning-model <think> blocks are stripped before json parse. Record the
CAPTCHA_E2E_HEADED toggle, drop the done roadmap items, keep the honest note
that headless reCAPTCHA v2 usually won't mint a token, and call out the single
package-lock.json lockfile.
This commit is contained in:
2026-06-07 14:35:05 +01:00
parent b3c32864e9
commit bfbb78383d
+35 -11
View File
@@ -53,7 +53,7 @@ Copy `.env.example` as a starting point.
| Variable | Required | Default | Notes | | Variable | Required | Default | Notes |
|----------|----------|---------|-------| |----------|----------|---------|-------|
| `CAPTCHA_LLM_PROVIDER` | yes | — | `anthropic` \| `openai` \| `openai-compatible` \| `gemini` | | `CAPTCHA_LLM_PROVIDER` | yes | — | `anthropic` \| `openai` \| `openai-compatible` \| `gemini` (all four fully implemented) |
| `CAPTCHA_LLM_BASE_URL` | for `openai-compatible` | provider default | Endpoint override (local / Ollama / OpenRouter / gateway) | | `CAPTCHA_LLM_BASE_URL` | for `openai-compatible` | provider default | Endpoint override (local / Ollama / OpenRouter / gateway) |
| `CAPTCHA_LLM_API_KEY` | yes\* | — | \*May be **empty** for a keyless local/gateway endpoint **when `BASE_URL` is set** | | `CAPTCHA_LLM_API_KEY` | yes\* | — | \*May be **empty** for a keyless local/gateway endpoint **when `BASE_URL` is set** |
| `CAPTCHA_LLM_MODEL` | yes | — | Vision-capable model id (see compatibility notes) | | `CAPTCHA_LLM_MODEL` | yes | — | Vision-capable model id (see compatibility notes) |
@@ -66,6 +66,12 @@ Copy `.env.example` as a starting point.
> **Keyless gateways:** if you point `CAPTCHA_LLM_BASE_URL` at an OpenAI-compatible gateway > **Keyless gateways:** if you point `CAPTCHA_LLM_BASE_URL` at an OpenAI-compatible gateway
> that does not require auth, leave `CAPTCHA_LLM_API_KEY` empty — startup will accept it. > that does not require auth, leave `CAPTCHA_LLM_API_KEY` empty — startup will accept it.
> **Gemini:** the `gemini` provider is **fully implemented** against Google's native
> `generateContent` wire format (vision *and* audio) and is unit-tested. Live use needs a
> real Google Gemini API key (`generativelanguage.googleapis.com`) — the project's
> OpenAI-compatible test gateway can't exercise the native Gemini path, so it is covered by
> unit tests against a mock endpoint rather than the live e2e suite.
## Tools ## Tools
All nine tools are registered in `internal/mcp/server.go`. Every image/audio input accepts All nine tools are registered in `internal/mcp/server.go`. Every image/audio input accepts
@@ -78,7 +84,7 @@ All nine tools are registered in `internal/mcp/server.go`. Every image/audio inp
| `solve_audio_captcha` | `audio`, `language?` | `{text,confidence}`; errors clearly if provider has no transcription | | `solve_audio_captcha` | `audio`, `language?` | `{text,confidence}`; errors clearly if provider has no transcription |
| `solve_grid_captcha` | `screenshot`, `instruction`, `rows`, `cols`, `image_width?`, `image_height?`, `captcha_type?` | `{tiles,centroids?,confidence,recheck_recommended}` (reCAPTCHA v2 / hCaptcha) | | `solve_grid_captcha` | `screenshot`, `instruction`, `rows`, `cols`, `image_width?`, `image_height?`, `captcha_type?` | `{tiles,centroids?,confidence,recheck_recommended}` (reCAPTCHA v2 / hCaptcha) |
| `solve_rotation_captcha` | `screenshot`, `instruction?` | `{choice,rotations,confidence}` (FunCaptcha, best-effort) | | `solve_rotation_captcha` | `screenshot`, `instruction?` | `{choice,rotations,confidence}` (FunCaptcha, best-effort) |
| `get_stealth_script` | `engine?` = `playwright`\|`cdp`\|`generic` | `{script,apply,included_evasions}` — JS init script + how to inject it | | `get_stealth_script` | `engine?` = `playwright`\|`cdp`\|`generic`, `os?`, `browser?`, `locale?`, `seed?` | `{script,apply,fingerprint,included_evasions}` — JS init script (templated to match `fingerprint`) + how to inject it |
| `generate_fingerprint` | `os?`, `browser?`, `locale?`, `seed?` | `{fingerprint,header_set}` — coherent identity + matching headers (seeded = stable) | | `generate_fingerprint` | `os?`, `browser?`, `locale?`, `seed?` | `{fingerprint,header_set}` — coherent identity + matching headers (seeded = stable) |
| `plan_interaction` | `actions`, `seed?` | humanized mouse/keyboard timeline (Bézier paths, jitter, cadence) | | `plan_interaction` | `actions`, `seed?` | humanized mouse/keyboard timeline (Bézier paths, jitter, cadence) |
| `solver_info` | — | configured provider/model + per-type capability flags | | `solver_info` | — | configured provider/model + per-type capability flags |
@@ -91,6 +97,12 @@ All nine tools are registered in `internal/mcp/server.go`. Every image/audio inp
(set `CAPTCHA_LLM_AUDIO_MODEL`). (set `CAPTCHA_LLM_AUDIO_MODEL`).
- `plan_interaction` is designed to pair with grid centroids: feed it `click` actions at the - `plan_interaction` is designed to pair with grid centroids: feed it `click` actions at the
tile centroids to produce human-looking pointer motion. tile centroids to produce human-looking pointer motion.
- `get_stealth_script` accepts `os` / `browser` / `locale` / `seed` and returns a
`fingerprint` field. The injected evasion script's WebGL vendor/renderer,
`navigator.platform`, and `navigator.languages` are **templated to match that
fingerprint** (coherent), so the script and the identity tell the same story. Inject the
`script` and apply the returned `fingerprint` together — or call `get_stealth_script` and
`generate_fingerprint` with the **same `seed`** to get an identical, coherent pair.
## Captcha-type matrix ## Captcha-type matrix
@@ -190,6 +202,9 @@ npx playwright install chromium
make e2e-browser make e2e-browser
``` ```
> Node deps are pinned by a single lockfile, **`package-lock.json`** (npm). Use `npm` to
> install so the lockfile stays canonical.
Two paths (`test/e2e/playwright/*.mjs`, wrapped by `test/e2e/browser_test.go`): Two paths (`test/e2e/playwright/*.mjs`, wrapped by `test/e2e/browser_test.go`):
- **Text captcha (`solve-text.mjs`) — verified end-to-end.** Screenshots the demo's - **Text captcha (`solve-text.mjs`) — verified end-to-end.** Screenshots the demo's
@@ -201,7 +216,10 @@ Two paths (`test/e2e/playwright/*.mjs`, wrapped by `test/e2e/browser_test.go`):
`plan_interaction` → humanized clicks over the tile grid, and reads `plan_interaction` → humanized clicks over the tile grid, and reads
`g-recaptcha-response`. Real Google reCAPTCHA commonly resists headless automation, so `g-recaptcha-response`. Real Google reCAPTCHA commonly resists headless automation, so
this path **logs the outcome and exits 0 even with no token** — it fails only on a real this path **logs the outcome and exits 0 even with no token** — it fails only on a real
script/transport error. script/transport error. Set **`CAPTCHA_E2E_HEADED=1`** to launch a visible, slow-mo
browser for a real-profile attempt that improves the odds of Google minting a token.
Headless reCAPTCHA v2 usually **won't** mint a token — that is inherent to Google's
defenses, not a bug in this harness.
## Compatibility notes ## Compatibility notes
@@ -209,15 +227,20 @@ Two paths (`test/e2e/playwright/*.mjs`, wrapped by `test/e2e/browser_test.go`):
with `max_completion_tokens` when a model (e.g. GPT-5.x) rejects `max_tokens`. This works with `max_completion_tokens` when a model (e.g. GPT-5.x) rejects `max_tokens`. This works
transparently across old and new OpenAI-style backends — you don't configure anything. transparently across old and new OpenAI-style backends — you don't configure anything.
- **Prefer a vision-capable model** for the image/grid tools (e.g. `openai/gpt-5.4`, - **Prefer a vision-capable model** for the image/grid tools (e.g. `openai/gpt-5.4`,
`zai/GLM-4.6V-FlashX`). Reasoning models that emit `<think>…</think>` still work `zai/GLM-4.6V-FlashX`). Reasoning models that emit `<think>…</think>` (or
(responses are JSON-extracted), but non-reasoning vision models give cleaner output. `<thinking>…</thinking>`) are now **handled** — the scratchpad block is stripped *before*
JSON extraction, so a JSON-looking object inside the reasoning never gets mistaken for the
answer. Non-reasoning vision models still give the lowest latency.
- **TLS/JA3 + HTTP/2 fingerprints are browser/proxy-level.** The stealth tools only - **TLS/JA3 + HTTP/2 fingerprints are browser/proxy-level.** The stealth tools only
*advise* on these — they cannot change them. To control them, terminate through a *advise* on these — they cannot change them. To control them, terminate through a
fingerprint-aware proxy or a browser build that emits the JA3/H2 profile you want. fingerprint-aware proxy or a browser build that emits the JA3/H2 profile you want.
## Roadmap / not yet built ## Roadmap / not yet built
Two pieces are **designed but deferred** (see The **Gemini provider** and **WebGL/fingerprint coherence** are now **done** (see the
Provider and Tools sections above); they are no longer on this list.
One piece remains **designed but deferred** (see
[`docs/superpowers/specs/`](./docs/superpowers/specs) and [`docs/superpowers/specs/`](./docs/superpowers/specs) and
[`docs/superpowers/plans/`](./docs/superpowers/plans)): [`docs/superpowers/plans/`](./docs/superpowers/plans)):
@@ -226,8 +249,9 @@ Two pieces are **designed but deferred** (see
CI without hitting real sites. A **live** browser harness already exists (`make CI without hitting real sites. A **live** browser harness already exists (`make
e2e-browser`, see [Testing](#testing)): it targets the 2captcha demo, is e2e-browser`, see [Testing](#testing)): it targets the 2captcha demo, is
network/browser-gated, verifies the text path end-to-end against the demo's success network/browser-gated, verifies the text path end-to-end against the demo's success
indicator, and runs the reCAPTCHA v2 path best-effort. The remaining work is the indicator, and runs the reCAPTCHA v2 path best-effort (with an optional
offline, deterministic local-page variant for CI. `CAPTCHA_E2E_HEADED=1` real-profile attempt). The remaining work is the offline,
- **Gemini provider** — a stub exists (`internal/llm/gemini.go`); the `generateContent` deterministic local-page variant for CI.
wire format still needs verification against current Google docs before it ships. Use
`openai` / `openai-compatible` / `anthropic` in the meantime. > Note: headless reCAPTCHA v2 usually won't mint a token regardless of harness quality —
> that is Google's anti-automation defense working as intended, not a defect here.