feat(sleep): support OpenAI-compatible endpoints (DeepSeek, vLLM) in azure_openai backend#129
Conversation
|
@microsoft-github-policy-service agree [company="{ALFRED KOLAKKAL}"] |
|
@microsoft-github-policy-service agree company="ALFRED KOLAKKAL" |
|
@microsoft-github-policy-service agree |
38f4880 to
f14b802
Compare
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.
f14b802 to
af33f6c
Compare
Yif-Yang
left a comment
There was a problem hiding this comment.
Requesting changes because the documented CLI path fails, the watchdog can report false success, error state is inconsistent, the managed-identity endpoint path needs a security guard, and the new behavior has no tests. Please address the detailed maintainer comment above.
Replacing this review with a corrected protocol-scoped review. Azure Responses testing is not required for this OpenAI-compatible Chat Completions contribution.
Yif-Yang
left a comment
There was a problem hiding this comment.
Thanks for contributing this — adding standard OpenAI-compatible Chat Completions support to SkillOpt-Sleep is a useful improvement, and your reported DeepSeek end-to-end run is relevant validation for that scope.
A clarification from our side: we do not require this PR to be tested against Azure Responses API. Azure Responses and OpenAI-compatible Chat Completions are different protocols, so forcing an Azure Responses test here would be the wrong acceptance criterion. A compliant OpenAI-compatible endpoint such as DeepSeek or vLLM is the appropriate live smoke test, and the DeepSeek result already described in this PR is sufficient for the live-provider portion.
Before approval, please address this smaller, protocol-scoped set of integration issues:
- Expose the feature through the documented CLI path. The documented command uses
--backend azure_openai, but that value is currently rejected by the choices inskillopt_sleep/__main__.py. - Propagate failures from the example runner.
runner.pyignores the child return code, sowatchdog.pycan report a failed sleep run as successful. - Make error state reliable. Clear
last_call_errorafter a recovered successful retry, and set a useful diagnostic when all responses are empty. - Keep compatible auth separate from managed identity. A non-Azure custom endpoint should require explicit compatible/API-key auth; setting a custom endpoint must not accidentally send an Azure managed-identity bearer token to an arbitrary host.
- Keep generic behavior provider-neutral. The DeepSeek-specific
thinkingbody and hard-coded token limit should be opt-in/configured (or split into a provider-specific follow-up) rather than inferred solely from a model-name substring. The generic path only needs to honor the standard OpenAI-compatible request contract. - Align documentation with implementation. Either implement the optimizer/target-prefixed environment variables claimed by the docs or remove that claim.
- Add focused no-network tests for CLI acceptance, compatible-vs-Azure client selection, endpoint/auth handling, request kwargs, retry-success error clearing, empty-response diagnostics, and runner exit-code propagation.
Once these deterministic tests pass along with the full suite, no additional Azure live test is needed. We would be happy to re-review promptly and merge this through your original PR so your authorship and contribution history remain intact.
… kwargs, tests Addresses maintainer review on the OpenAI-compatible endpoints PR: 1. CLI: accept --backend azure_openai in skillopt_sleep/__main__.py (the documented command was rejected by the argparse choices). 2. Example runner: exit with the child's return code so watchdog/supervisors see a failed sleep run as a failure. 3. Error state: clear last_call_error when a retry recovers; set an explicit "empty response on all N attempts" diagnostic when every attempt returns empty text. 4. Security guard: the managed-identity path now refuses to send an Azure AD bearer token to any endpoint outside *.openai.azure.com / *.cognitiveservices.azure.com — a custom endpoint requires explicit AZURE_OPENAI_AUTH_MODE=openai_compatible + API key. 5. Provider-neutral requests: compat mode sends only the standard contract (max_tokens, default 8192 via SKILLOPT_SLEEP_COMPAT_MAX_TOKENS); provider-specific body fields are opt-in via SKILLOPT_SLEEP_CHAT_EXTRA_BODY (JSON) — the deepseek model-name inference is removed. 6. Docs: removed the unimplemented OPTIMIZER_*/TARGET_* env-var claim; added a configuration reference matching the implementation exactly. 7. Tests: tests/test_azure_openai_compat.py — 17 deterministic no-network unittest cases covering CLI acceptance, compat-vs-Azure client selection, endpoint resolution, the credential guard, request kwargs (opt-in extra body / token cap), retry-success error clearing, empty-response diagnostics, and runner exit-code propagation. Re-verified live against DeepSeek (deepseek-v4-pro, openai_compatible mode) after the rework: client type OpenAI, completion returned, no error state.
|
Thanks for the fast, clearly-scoped review — all seven items are addressed in 4ff77b7.
Verification: the new file passes 17/17; the full suite on this branch shows no regressions vs. a pristine Agreed on scope — no Azure Responses testing was done or claimed for this protocol. Ready for re-review. |
Yif-Yang
left a comment
There was a problem hiding this comment.
Thank you for the careful rework. Commit 4ff77b7 genuinely addresses the seven points from the previous review: the CLI path is reachable, runner failures propagate, error state is reliable, provider-specific fields are opt-in, the docs now match the implementation, and the new focused coverage is useful.
We reran the 17 focused tests and the full suite against current main, and also exercised the plain OpenAI client against a local HTTP server. The OpenAI-compatible request path works. This remains a Chat Completions review; Azure Responses testing is not required.
Two narrowly scoped issues remain before merge:
- Managed-identity endpoints must require HTTPS.
_is_azure_host()currently validates only the hostname suffix. Consequentlyhttp://foo.openai.azure.compasses the guard, and the AzureOpenAI SDK accepts that URL, allowing an AAD bearer token to be sent over plaintext HTTP. Please require bothparsed.scheme == "https"and an approved Azure hostname, with a regression test that rejects an HTTP Azure-looking endpoint. - Keep
SKILLOPT_SLEEP_CHAT_EXTRA_BODYcompat-only. The current unconditionalif self.chat_extra_bodyalso attaches it in managed-identity Azure mode, despite the new documentation and compatibility promise. Please gate it with compat mode (or otherwise make the Azure behavior explicit) and add an Azure-mode test.
These are directly within the credential-safety and backward-compatibility contract of this PR. Once they are addressed in this original PR, we can re-review quickly and preserve your authorship and contribution history.
What
Enables the SkillOpt-Sleep
azure_openaibackend to drive any OpenAI-compatible chat-completions endpoint — e.g. DeepSeek's hosted API or a self-hosted vLLM/Ollama server — alongside the existing native Azure OpenAI managed-identity path. The default Azure path is unchanged and fully backward-compatible.Why
Pointing the
azure_openaibackend at a non-Azure endpoint was impossible: the endpoint was resolved only from a hardcoded_AZURE_ENDPOINTStable, and_get_client()always built anAzureOpenAIclient. That client rewrites request URLs with Azure-only structure (?api-version=…query params + deployment path segments), which non-Azure OpenAI-compatible servers reject with404 Resource not found. SkillOpt-Sleep then gets an empty response, the judge scores it0.0, and every night reportsbaseline 0.0 → candidate 0.0with no usable diagnostic.Notably, the sibling module
skillopt/model/azure_openai.pyalready supports anopenai_compatibleauth mode; this change bringsskillopt_sleep/backend.pyin line with it.What changed (
skillopt_sleep/backend.py, +48 / −14)AZURE_OPENAI_ENDPOINT— order is nowexplicit arg→AZURE_OPENAI_ENDPOINTenv → the built-in table.openai_compatibleauth mode — whenAZURE_OPENAI_AUTH_MODE=openai_compatible(alsocompat/openai),_get_client()builds a plainopenai.OpenAI(base_url=…)client, avoiding the Azure URL rewriting._call()sendsmax_tokens+extra_body={"thinking": {"type": "enabled"}}fordeepseek*deployments, and records the last exception inself.last_call_errorso a failed night is diagnosable instead of a silent empty→0.0.Plus documentation:
docs/sleep/openai-compatible-endpoints.mdand sanitizeddocs/sleep/examples/runner + watchdog scripts showing an Antigravity IDE + DeepSeek integration (no keys, no hardcoded personal paths).How to test
To pull this branch locally:
Results (verified on Windows 11,
deepseek-v4-pro)OpenAI, no404,last_call_errorempty.0.250 → 1.000and accepted a DeepSeek-authored skill edit (accept_new_best);diagnostics.jsonshows"backend": "azure_openai"with non-zero tokens and emptycall_error— a genuine optimization night vs. the prior all-0.0nights caused by the endpoint bug.0.3 → 0.3), confirming normal gate behavior on the new backend.Notes
AZURE_OPENAI_AUTH_MODEunset, behavior is identical to before (managed-identityAzureOpenAI).claudeCLI through a local Anthropic-compatible proxy and is documented as illustrative/unverified, not a supported path.