)]}'
{
  "commit": "6827e4acba28e67e00efead61b37770d79fecac0",
  "tree": "756e979ca36534e7dad0685313dd76869a9eb19c",
  "parents": [
    "925e3fe7593a702a83dd74cb9d0d9fbedaff3bb8"
  ],
  "author": {
    "name": "Jacek Centkowski",
    "email": "geminica.programs@gmail.com",
    "time": "Wed May 13 08:53:20 2026 +0200"
  },
  "committer": {
    "name": "Jacek Centkowski",
    "email": "geminica.programs@gmail.com",
    "time": "Thu May 14 11:52:10 2026 -0700"
  },
  "message": "Introduce AI review chat integration with OpenRouter\n\nAdd a Groovy script implementation of AiReviewProvider that wires the\nGerrit AI Code Review chat to OpenRouter (https://openrouter.ai/), a\nunified gateway exposing 300+ LLMs from Anthropic, OpenAI, Google,\nDeepSeek, Meta, Qwen, xAI and others behind a single OpenAI-compatible\nAPI.\n\nThe provider builds the dropdown at runtime from a small static list of\nOpenRouter floating aliases (`~vendor/model-latest`, always-fresh paid\noptions) combined with a live `/api/v1/models` query that picks the\nhighest-versioned DeepSeek `*-pro` slug and the top five free-tier\nslugs by a code-review heuristic (id keywords, reasoning support,\nbig-vendor namespace, context length). The catalog result is cached\nfor a day via Guava\u0027s memoizeWithExpiration and invalidated when a\nreview call returns HTTP 404 (a previously listed slug went away\nupstream). On catalog fetch failure the dropdown falls back to the\nstatic floating aliases so it is never empty.\n\nThe script also handles a few OpenRouter-specific quirks:\n\n* Single retry on HTTP 429 with a fixed back-off, followed by a\n  user-facing rate-limit notice rendered as the assistant reply when\n  the retry budget is exhausted, instead of surfacing a generic\n  HTTP 500 in the chat panel.\n* Strip an outer triple-backtick markdown fence when the entire reply\n  is wrapped in one, since gr-formatted-text would otherwise render\n  the response as a literal code block (observed with the\n  openai/gpt-oss-* models).\n* Prefix every non-empty reply with a newline so the response renders\n  on its own line, separated from the \"Gathering file contents and\n  calling AI model ...\" placeholder produced by the provider plugin.\n\nAdd a companion README documenting installation, the dynamic model\nselection scheme, and OpenRouter API key setup.\n\nChange-Id: Ieaae90717b5c56e053d31eda4f4b286d7c1a366c\n",
  "tree_diff": [
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "30f75f337d5c4f0e8336360c488438929f0a824c",
      "new_mode": 33188,
      "new_path": "ai/ai-review-agent-openrouter-1.0.groovy"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "ab25f968c3405dd47d2df8152e45d0819ae4e0d8",
      "new_mode": 33188,
      "new_path": "ai/ai-review-agent-openrouter.md"
    }
  ]
}
