Files
chatballs/apps
Andrey a0d2d61954 ♻️ refactor(ai): extract shared OpenAI-compatible HTTP layer
OpenRouter, the generic Custom adapter and (in track B) CustoAI all speak the
same Chat Completions shape: POST /chat/completions, POST /embeddings,
Authorization: Bearer <key>, response with choices[0].message.content and usage.
The transport and response parsing were duplicated in OpenRouterProvider and
would be duplicated again by CustoAI.

Move post_json / get_json / chat_completions / embeddings into a new
ai/provider/openai_http.py module that owns the HTTP transport and OpenAI-shape
parsing. Adapters keep their product semantics only:

- OpenRouterProvider delegates chat (with usage.include=true to read usage.cost)
  and embed to openai_http; it is now a thin adapter, not a transport owner.
- CustomProvider inherits the delegation unchanged.

Update OpenRouterProviderProxyTests to mock openai_http.build_opener (the new
transport location) and add the model field to the fake response so the parsed
ChatResult matches.

Verified: 13/13 integrations tests, 47/47 ai tests.
2026-07-17 04:26:46 +03:00
..