towards-ai-deploy commited on
Commit
ae1e375
·
1 Parent(s): 0c08d1a

Deploy tai-helper ea13623

Browse files
Files changed (5) hide show
  1. .env.example +5 -0
  2. README.md +10 -0
  3. tai_helper/llm.py +17 -0
  4. tai_helper/settings.py +10 -0
  5. tests/test_llm.py +63 -0
.env.example CHANGED
@@ -11,6 +11,11 @@ HELPER_SITE_WIDE_HOSTS=towardsai.com,www.towardsai.com
11
  HELPER_PRIMARY_BASE_URL=https://openrouter.ai/api/v1
12
  HELPER_PRIMARY_API_KEY=
13
  HELPER_PRIMARY_MODEL=deepseek/deepseek-v4-flash
 
 
 
 
 
14
 
15
  # Backup model: Gemini 3.7 Flash, on Google's API rather than OpenRouter so the
16
  # fallback does not share a gateway with the primary.
 
11
  HELPER_PRIMARY_BASE_URL=https://openrouter.ai/api/v1
12
  HELPER_PRIMARY_API_KEY=
13
  HELPER_PRIMARY_MODEL=deepseek/deepseek-v4-flash
14
+ # OpenRouter serves one model id from many independent hosts at different
15
+ # quantisations, and they are NOT interchangeable for extractive grounding.
16
+ # Unpinned routing sent every request to one host that answered 0/6 on the
17
+ # main starter prompt. Preference order, first entry wins; fallbacks stay on.
18
+ HELPER_OPENROUTER_PROVIDER_ORDER=novita
19
 
20
  # Backup model: Gemini 3.7 Flash, on Google's API rather than OpenRouter so the
21
  # fallback does not share a gateway with the primary.
README.md CHANGED
@@ -49,6 +49,16 @@ out of balance and took the helper down, while OpenRouter draws on a shared
49
  balance that is kept topped up. `HELPER_PRIMARY_MODEL` can name any OpenRouter
50
  model without code changes.
51
 
 
 
 
 
 
 
 
 
 
 
52
  Gemini 3.7 Flash is the fallback, deliberately kept on Google's own API rather
53
  than routed through OpenRouter, so the backup does not share a gateway with the
54
  primary. It only runs when the primary fails and it passes the grounding
 
49
  balance that is kept topped up. `HELPER_PRIMARY_MODEL` can name any OpenRouter
50
  model without code changes.
51
 
52
+ **Pin the OpenRouter host.** OpenRouter serves one model id from many
53
+ independent providers at different quantisations, and they are not
54
+ interchangeable for this workload. Measured on identical grounding prompts, one
55
+ host answered 3/3 while another answered 0/3, and the host the default routing
56
+ kept choosing returned `not_found` on the main starter prompt every single time
57
+ — 0/6 in production, 6/6 once pinned. `HELPER_OPENROUTER_PROVIDER_ORDER` sets
58
+ the preference order; `require_parameters` additionally drops hosts that would
59
+ ignore `response_format` and answer with prose. Fallbacks stay enabled, so one
60
+ host going down degrades quality rather than taking the helper offline.
61
+
62
  Gemini 3.7 Flash is the fallback, deliberately kept on Google's own API rather
63
  than routed through OpenRouter, so the backup does not share a gateway with the
64
  primary. It only runs when the primary fails and it passes the grounding
tai_helper/llm.py CHANGED
@@ -638,6 +638,22 @@ def _reasoning_control() -> dict[str, Any]:
638
  return {"reasoning": {"enabled": settings.primary_reasoning_enabled}}
639
 
640
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
641
  def _generate_primary_answer(prompt: str) -> LLMResult:
642
  if not settings.primary_api_key:
643
  raise RuntimeError("HELPER_PRIMARY_API_KEY is not configured")
@@ -652,6 +668,7 @@ def _generate_primary_answer(prompt: str) -> LLMResult:
652
  {"role": "user", "content": prompt},
653
  ],
654
  **_reasoning_control(),
 
655
  "response_format": {"type": "json_object"},
656
  "temperature": DEFAULT_TEMPERATURE,
657
  "max_tokens": settings.max_output_tokens,
 
638
  return {"reasoning": {"enabled": settings.primary_reasoning_enabled}}
639
 
640
 
641
+ def _provider_routing() -> dict[str, Any]:
642
+ """Constrain which OpenRouter host serves the request.
643
+
644
+ ``require_parameters`` drops hosts that do not honour what is sent, so a
645
+ host that ignores ``response_format`` cannot answer with prose that then
646
+ fails to parse. The preference order puts a host measured as reliable for
647
+ extractive grounding first, with fallbacks left on so a single host being
648
+ down degrades quality instead of taking the helper offline.
649
+ """
650
+
651
+ routing: dict[str, Any] = {"require_parameters": True, "allow_fallbacks": True}
652
+ if settings.openrouter_provider_order:
653
+ routing["order"] = list(settings.openrouter_provider_order)
654
+ return {"provider": routing}
655
+
656
+
657
  def _generate_primary_answer(prompt: str) -> LLMResult:
658
  if not settings.primary_api_key:
659
  raise RuntimeError("HELPER_PRIMARY_API_KEY is not configured")
 
668
  {"role": "user", "content": prompt},
669
  ],
670
  **_reasoning_control(),
671
+ **_provider_routing(),
672
  "response_format": {"type": "json_object"},
673
  "temperature": DEFAULT_TEMPERATURE,
674
  "max_tokens": settings.max_output_tokens,
tai_helper/settings.py CHANGED
@@ -103,6 +103,16 @@ class Settings:
103
  or DEFAULT_PRIMARY_MODEL
104
  )
105
  )
 
 
 
 
 
 
 
 
 
 
106
  gemini_api_key: str = field(
107
  default_factory=lambda: os.getenv("GEMINI_API_KEY", "").strip()
108
  )
 
103
  or DEFAULT_PRIMARY_MODEL
104
  )
105
  )
106
+ # OpenRouter serves one model id from many independent hosts at different
107
+ # quantisations, and they are not interchangeable for extractive grounding:
108
+ # measured on the same prompts, one host answered 3/3 while another
109
+ # answered 0/3 and a third returned not_found every time. Left unpinned,
110
+ # routing silently picks one and answer quality swings with it.
111
+ openrouter_provider_order: tuple[str, ...] = field(
112
+ default_factory=lambda: _csv_env(
113
+ "HELPER_OPENROUTER_PROVIDER_ORDER", "novita"
114
+ )
115
+ )
116
  gemini_api_key: str = field(
117
  default_factory=lambda: os.getenv("GEMINI_API_KEY", "").strip()
118
  )
tests/test_llm.py CHANGED
@@ -260,3 +260,66 @@ def test_openrouter_style_disables_reasoning_with_openrouter_parameter(
260
  assert captured["reasoning"] == {"enabled": False}
261
  assert "thinking" not in captured
262
  assert captured["model"] == "deepseek/deepseek-v4-flash"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
  assert captured["reasoning"] == {"enabled": False}
261
  assert "thinking" not in captured
262
  assert captured["model"] == "deepseek/deepseek-v4-flash"
263
+
264
+
265
+ def test_openrouter_request_pins_provider_routing(monkeypatch) -> None:
266
+ """One OpenRouter model id is served by many independent hosts.
267
+
268
+ They are not interchangeable for extractive grounding: on identical prompts
269
+ one host answered 3/3 while another answered 0/3, and the host the default
270
+ routing kept selecting returned not_found every time. require_parameters
271
+ also drops hosts that would ignore response_format and reply with prose.
272
+ """
273
+
274
+ captured: dict[str, object] = {}
275
+
276
+ def fake_post(_url, **kwargs):
277
+ captured.update(kwargs["json"])
278
+ return FakeOpenRouterResponse(
279
+ 200, {"choices": [{"message": {"content": "{}"}}]}, ""
280
+ )
281
+
282
+ monkeypatch.setattr(
283
+ llm,
284
+ "settings",
285
+ Settings(
286
+ primary_api_key="openrouter-key",
287
+ openrouter_provider_order=("novita", "alibaba"),
288
+ ),
289
+ )
290
+ monkeypatch.setattr(llm.requests, "post", fake_post)
291
+
292
+ llm.generate_answer("Visitor prompt")
293
+
294
+ assert captured["provider"] == {
295
+ "require_parameters": True,
296
+ "allow_fallbacks": True,
297
+ "order": ["novita", "alibaba"],
298
+ }
299
+
300
+
301
+ def test_openrouter_routing_omits_order_when_unset(monkeypatch) -> None:
302
+ """An empty order must not pin routing to nothing and 404 the request."""
303
+
304
+ captured: dict[str, object] = {}
305
+
306
+ def fake_post(_url, **kwargs):
307
+ captured.update(kwargs["json"])
308
+ return FakeOpenRouterResponse(
309
+ 200, {"choices": [{"message": {"content": "{}"}}]}, ""
310
+ )
311
+
312
+ monkeypatch.setattr(
313
+ llm,
314
+ "settings",
315
+ Settings(primary_api_key="openrouter-key", openrouter_provider_order=()),
316
+ )
317
+ monkeypatch.setattr(llm.requests, "post", fake_post)
318
+
319
+ llm.generate_answer("Visitor prompt")
320
+
321
+ assert captured["provider"] == {
322
+ "require_parameters": True,
323
+ "allow_fallbacks": True,
324
+ }
325
+ assert "order" not in captured["provider"]