
Baoyu Danger Gemini Web
Wire agent workflows to Google Gemini via the unofficial web client for chat, gems, and image generation when API keys are not an option.
Overview
Baoyu-danger-gemini-web is an agent skill for the Build phase that connects workflows to Google Gemini through an unofficial web client for chat, gems, and image generation.
Install
npx skills add https://github.com/xy121718/baoyu-skills --skill baoyu-danger-gemini-webWhat is this skill?
- TypeScript Gemini web client with GemMixin for custom gems and RPC-style calls
- Handles auth rotation (1PSIDTS), cookies, uploads, and structured error types (auth, usage limits, timeouts)
- Supports generated and web-sourced images with explicit ImageGenerationError paths
- Configurable timeouts, auto-refresh, and verbose logging for long agent sessions
- Marked “danger” tier—unofficial web surface, not the stable Google AI API
- Typed error surface including AuthError, UsageLimitExceeded, ImageGenerationError, and TemporarilyBlocked
Adoption & trust: 1 installs on skills.sh; 94 GitHub stars; 1/3 security scanners passed (skills.sh audits); trending (+100% hot-view momentum).
What problem does it solve?
You need Gemini multimodal output in an agent pipeline but only have browser cookie auth or cannot use the official Gemini API yet.
Who is it for?
Indie builders prototyping AI features, content automation, or image experiments inside agent tooling during active development.
Skip if: Production apps requiring SLA-backed APIs, strict data residency, or teams unwilling to manage cookie-based session risk.
When should I use this skill?
When building agent workflows that must call Gemini via web session auth for chat, gems, or images during integration work.
What do I get? / Deliverables
Your agent can call Gemini web endpoints with rotated session auth and typed errors so you can prototype generative features before moving to a supported API.
- Gemini web API calls from agent workflows
- Parsed model outputs and generated images where supported
Recommended Skills
Journey fit
This is a third-party Gemini web integration used while assembling product features and agent capabilities during Build. External LLM and image endpoints belong under integrations rather than core backend auth or frontend UI work.
How it compares
Integration skill for unofficial Gemini web access—not a first-party Google AI SDK or MCP server.
Common Questions / FAQ
Who is baoyu-danger-gemini-web for?
Developers building agent or content workflows who want Gemini (including gems and images) via web-session automation rather than official API keys.
When should I use baoyu-danger-gemini-web?
During Build/integrations while wiring generative steps into your product or agent—e.g. drafting marketing assets, testing image pipelines, or orchestrating gem-powered tasks before launch.
Is baoyu-danger-gemini-web safe to install?
Treat it as high-risk unofficial access: review the Security Audits panel on this page, never commit live cookies to git, and prefer official APIs for production.
SKILL.md
READMESKILL.md - Baoyu Danger Gemini Web
import { Endpoint, ErrorCode, Headers, Model } from './constants.js'; import { GemMixin } from './components/gem-mixin.js'; import { APIError, AuthError, GeminiError, ImageGenerationError, ModelInvalid, TemporarilyBlocked, TimeoutError, UsageLimitExceeded, } from './exceptions.js'; import { Candidate, Gem, GeneratedImage, ModelOutput, RPCData, WebImage } from './types/index.js'; import { extract_json_from_response, get_access_token, get_nested_value, logger, parse_file_name, rotate_1psidts, rotate_tasks, fetch_with_timeout, sleep, upload_file, write_cookie_file, resolveGeminiWebCookiePath, } from './utils/index.js'; type InitOptions = { timeout?: number; auto_close?: boolean; close_delay?: number; auto_refresh?: boolean; refresh_interval?: number; verbose?: boolean; }; type RequestKwargs = RequestInit & { timeout_ms?: number }; function normalize_headers(h?: HeadersInit): Record<string, string> { if (!h) return {}; if (Array.isArray(h)) return Object.fromEntries(h.map(([k, v]) => [k, v])); if (h instanceof Headers) { const out: Record<string, string> = {}; h.forEach((v, k) => { out[k] = v; }); return out; } return { ...(h as Record<string, string>) }; } function collect_strings(root: unknown, accept: (s: string) => boolean, limit: number = 20): string[] { const out: string[] = []; const seen = new Set<string>(); const stack: unknown[] = [root]; while (stack.length > 0 && out.length < limit) { const v = stack.pop(); if (typeof v === 'string') { if (accept(v) && !seen.has(v)) { seen.add(v); out.push(v); } continue; } if (Array.isArray(v)) { for (let i = 0; i < v.length; i++) stack.push(v[i]); continue; } if (v && typeof v === 'object') { for (const val of Object.values(v as Record<string, unknown>)) stack.push(val); } } return out; } export class GeminiClient extends GemMixin { public cookies: Record<string, string> = {}; public proxy: string | null = null; public _running: boolean = false; public access_token: string | null = null; public timeout: number = 300; public auto_close: boolean = false; public close_delay: number = 300; public auto_refresh: boolean = true; public refresh_interval: number = 540; public kwargs: RequestInit; private close_timer: ReturnType<typeof setTimeout> | null = null; private refresh_abort: AbortController | null = null; constructor( secure_1psid: string | null = null, secure_1psidts: string | null = null, proxy: string | null = null, kwargs: RequestInit = {}, ) { super(); this.proxy = proxy; this.kwargs = kwargs; if (secure_1psid) { this.cookies['__Secure-1PSID'] = secure_1psid; if (secure_1psidts) this.cookies['__Secure-1PSIDTS'] = secure_1psidts; } } async init( timeoutOrOpts: number | InitOptions = 300, auto_close: boolean = false, close_delay: number = 300, auto_refresh: boolean = true, refresh_interval: number = 540, verbose: boolean = true, ): Promise<void> { const opts: InitOptions = typeof timeoutOrOpts === 'object' ? timeoutOrOpts : { timeout: timeoutOrOpts, auto_close, close_delay, auto_refresh, refresh_interval, verbose }; const timeout = opts.timeout ?? 300; const ac = opts.auto_close ?? false; const cd = opts.close_delay ?? 300; const ar = opts.auto_refresh ?? true; const ri = opts.refresh_interval ?? 540; const vb = opts.verbose ?? true; try { const [token, valid] = await get_access_token(this.cookies, this.proxy, vb); this.access_token = token; this.cookies = valid; this._running = true; this.timeout = timeout; this.auto_close = ac; this.close_delay = cd; if (this.auto_close) await this.reset_close_task(); this.auto_refresh = ar; this.refresh_interval = ri; const sid = th