Files
SkillOpt/docs/sleep/openai-compatible-endpoints.md
T
Alphaxalchemy af33f6c338 feat(sleep): support OpenAI-compatible endpoints in azure_openai backend
Let AzureOpenAIBackend drive any OpenAI-compatible chat-completions server
(DeepSeek, self-hosted vLLM/Ollama, ...) alongside native Azure deployments.

- __init__ resolves the endpoint as: explicit arg > AZURE_OPENAI_ENDPOINT env
  > the built-in _AZURE_ENDPOINTS table (previously a non-Azure endpoint could
  not be supplied at all).
- _get_client() builds a plain openai.OpenAI(base_url=...) client when
  AZURE_OPENAI_AUTH_MODE=openai_compatible, matching the auth mode already
  supported by the sibling skillopt/model/azure_openai.py. This avoids the
  AzureOpenAI SDK rewriting request URLs with Azure-only ?api-version= query
  params and deployment path segments, which non-Azure servers reject with 404.
- _call() sends max_tokens + extra_body thinking flag for deepseek* models and
  records the last exception in self.last_call_error so a failed night is
  diagnosable instead of collapsing to a silent empty->0 score.

Adds docs/sleep/openai-compatible-endpoints.md and sanitized example
runner/watchdog scripts documenting an Antigravity + DeepSeek integration.
The default managed-identity Azure path is unchanged.
2026-07-12 21:42:55 -06:00

5.5 KiB

OpenAI-compatible endpoints for SkillOpt-Sleep (DeepSeek, local vLLM, …)

This document describes a small enhancement to the azure_openai backend in skillopt_sleep/backend.py that lets SkillOpt-Sleep drive any OpenAI-compatible chat-completions endpoint — for example DeepSeek's hosted API or a self-hosted vLLM/Ollama server — in addition to native Azure OpenAI deployments. It also documents a concrete end-to-end integration: running the nightly sleep cycle inside the Antigravity IDE against DeepSeek.

What changed

Three focused changes in AzureOpenAIBackend (skillopt_sleep/backend.py), all backward-compatible — the default managed-identity path is unchanged:

  1. Endpoint resolution honors AZURE_OPENAI_ENDPOINT. __init__ now resolves the endpoint as explicit argAZURE_OPENAI_ENDPOINT env → the built-in _AZURE_ENDPOINTS table. Previously a non-Azure endpoint could not be supplied at all, so calls always went to a hardcoded *.openai.azure.com host.

  2. openai_compatible auth mode. When AZURE_OPENAI_AUTH_MODE=openai_compatible (also accepts compat/openai), _get_client() builds a plain openai.OpenAI(base_url=…) client instead of an AzureOpenAI client. This mirrors the auth mode already supported by the sibling skillopt/model/azure_openai.py module, so the two are consistent.

  3. DeepSeek request shape + error surfacing. _call() sends max_tokens plus extra_body={"thinking": {"type": "enabled"}} for deepseek* deployments (the DeepSeek reasoning models expect this), and records the last exception in self.last_call_error so a failed night is diagnosable instead of collapsing to a silent empty response scored 0.0.

Why the previous behavior failed on non-Azure servers

The AzureOpenAI SDK client rewrites request URLs with Azure-only structure — a ?api-version=… query string and deployment path segments. A non-Azure OpenAI-compatible server (DeepSeek, vLLM, …) does not recognize those routes and responds 404 Resource not found. SkillOpt-Sleep then receives an empty response, the judge scores it 0.0, and every night reports baseline 0.0 -> candidate 0.0 with no usable diagnostic. Selecting a plain OpenAI client via openai_compatible mode avoids the Azure URL rewriting and talks to the endpoint directly.

How to use it

Set four environment variables and run the cycle with --backend azure_openai:

export AZURE_OPENAI_AUTH_MODE=openai_compatible
export AZURE_OPENAI_ENDPOINT=https://api.deepseek.com   # no /v1, no trailing path
export AZURE_OPENAI_API_KEY=sk-...                       # your provider key
# optimizer/target dual-role overrides are also honored, e.g.
#   OPTIMIZER_AZURE_OPENAI_AUTH_MODE / TARGET_AZURE_OPENAI_AUTH_MODE, etc.

skillopt-sleep run \
  --backend azure_openai \
  --model deepseek-v4-pro \
  --project /path/to/your/project

The same pattern works for any OpenAI-compatible server — point AZURE_OPENAI_ENDPOINT at it and set a matching --model.

End-to-end integration: Antigravity + DeepSeek

The examples/ directory contains a sanitized reference of how this was wired into the Antigravity agent IDE so the sleep cycle runs unattended:

  • examples/runner.py — a thin launcher that loads a provider key from an .env file, exports the four variables above, and invokes skillopt-sleep run with the DeepSeek backend. It also implements a session-end hook that appends task-outcome metadata to a rollout-evidence log (wired to Antigravity's Stop hook) so future nights have richer sessions to mine.
  • examples/watchdog.py — a minimal supervisor loop that invokes the runner on a fixed interval (e.g. every 4 hours). On Windows this is registered as a Scheduled Task so it survives logout; on Linux/macOS a systemd timer or cron entry serves the same role.

Verified result

On a Windows 11 host, driving the cycle against deepseek-v4-pro in openai_compatible mode:

  • A direct backend smoke test returns a live completion (no 404, last_call_error empty, client type OpenAI).
  • A full nightly cycle mined tasks from real IDE sessions and the held-out validation gate moved from 0.250 → 1.000, accepting a DeepSeek-authored skill edit (accept_new_best). diagnostics.json for that night reports "backend": "azure_openai" with a non-empty token count and an empty call_error — i.e. a genuine optimization night, versus the prior all-0.0 nights that the endpoint bug produced.
  • A subsequent unattended night triggered by the watchdog completed the full chain (watchdog → runner → skillopt-sleep → DeepSeek) and the gate correctly rejected a non-improving proposal (0.3 → 0.3), confirming the validation gate behaves normally on the new backend.

A note on Gemini (optional, unverified fallback)

examples/runner.py also contains a fallback branch that, when only a Gemini key is present, routes the claude CLI backend through a local Anthropic-compatible proxy (e.g. LiteLLM on http://127.0.0.1:4000) by setting ANTHROPIC_BASE_URL/ANTHROPIC_API_KEY. There is no native Gemini backend in SkillOpt, and this proxy path was not independently validated in this work — it is included only as a configuration example. The verified, supported path in this document is DeepSeek via openai_compatible mode. Treat the Gemini branch as illustrative, not tested.