The Devin MCP server's backend enum only listed mock/claude/codex/copilot,
excluding the handoff backend that was merged to the engine in #125. This
made the subscription-friendly, no-API-key path unavailable to Devin users
while Claude Code had a dedicated /skillopt-sleep-handoff command for it.
Add "handoff" to the backend enum in _TOOL_SCHEMA so sleep_run accepts
backend: "handoff". The engine already handles the prompt/answer file loop
(exit code 3 + .skillopt-sleep-handoff/); the MCP server needs no special
handling — it passes through the engine output showing pending prompts.
Update the README, rules snippet, and test_backends_in_enum accordingly.
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.
Fix 1: Add [tool.setuptools.package-data] to pyproject.toml so that
all .md prompt files (generic prompts under skillopt/prompts/ and
env-specific prompts under skillopt/envs/*/prompts/) are included
in the wheel. Previously pip install from PyPI would fail with
FileNotFoundError on first prompt load.
Fix 2: Replace TemporaryDirectory context manager with mkdtemp +
shutil.rmtree(ignore_errors=True) in claude_backend._run_claude_print.
On Windows, the spawned claude/node subprocess still holds a handle
on the temp directory when the context manager tries to clean up,
causing WinError 32. Manual rmtree with ignore_errors=True works
on all Python versions >= 3.10.
Co-Authored-By: Claude <noreply@anthropic.com>
The LinearScheduler.known_decay_sequence test now reflects the new
t = (step-1)/(total_steps-1) contract where step 1 returns max_lr.
Updated docstrings for midpoint and early-step tests to match.
All 43 tests now pass against the updated formula.
LinearScheduler and CosineScheduler now guarantee step() returns max_lr
on the first call and min_lr on the total_steps-th call, using the
standard endpoint parameterisation t = (step-1)/(total_steps-1).
This resolves the inconsistent first-step semantics reported in review.
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.
Three filters to stop machine-generated prompts polluting the mined task
pool (they dominated ~80% of tasks on this machine):
- _is_meta_prompt: drop expanded slash-command bodies (<command-message>
tags or '# /' headers) — plugin self-invocations are not user intents
- _AGENT_SESSION_MARKERS + _is_agent_session: skip sessions whose first
prompt is another tool's agent brief (claude-mem observers, CLAUDE.md
critic sub-agents, SkillOpt-Sleep's own command body)
- load walk: skip <session>/subagents/ dirs and agent-*.jsonl files —
Agent-tool sidechain transcripts are Claude-authored, not user tasks
Verified: harvest went from 120 sessions / mostly-noise tasks to 55
sessions / 38 real user tasks.
Co-authored-by: codeL1985 <l@cypherlab.tech>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>