Commit Graph

82 Commits

Author SHA1 Message Date
Yif-Yang
b12b54cb30 fix(sleep): harden evidence log privacy 2026-07-21 17:25:52 +00:00
Alpha
08cb5a9cb6 feat(sleep): per-night evidence chain and live prompt registry
* skillopt_sleep/evidence.py — append-only, thread-safe, redacted
  evidence.jsonl per night: harvest sessions -> miner exchanges (verbatim
  prompt/reply) -> mined tasks with checks -> split assignment -> every
  replay attempt (phase-tagged, cache hits marked) -> per-task scores with
  failing checks named -> reflect exchanges + parsed edits -> gate trials
  and the final decision with its score arithmetic -> staged artifacts.
  Config-gated (evidence_log, default on; evidence_max_chars cap).

* skillopt_sleep/prompts.py — central registry of the four LLM prompt
  templates (miner/attempt/judge/reflect), byte-identical defaults to the
  previously inlined strings; user overrides in prompts.json take effect
  on the next model call (mtime-checked), no restart needed.

* cycle.py builds dual backends from config (optimizer_*/target_*),
  pre-creates the staging dir so evidence lands beside the report;
  staging.new_staging_dir() de-collides same-second runs;
  latest_staging() now skips non-adoptable (evidence-only) folders.

* tests/test_sleep_evidence.py — 8 no-network stdlib tests: chain
  completeness, redaction/truncation/ordering, disable flag, prompt
  override round-trip + live effect, no-tasks-night adoption guard.
2026-07-21 17:15:41 +00:00
Yif-Yang
717dedd5a9 fix(sleep): isolate Cursor backend environment 2026-07-21 17:14:05 +00:00
Yif-Yang
57c808d2d7 Merge upstream/main into feat/cursor-skillopt-sleep 2026-07-21 17:05:31 +00:00
James Davies
4aa59ed0a8 Guard Cursor file-edit rollouts with sandboxing 2026-07-20 21:15:04 +01:00
James Davies
8b1d75e6b8 Disable unverified Cursor Sleep tool replay 2026-07-20 21:14:39 +01:00
James Davies
586b1e3f6c Allow cursor to work with non-sleep Skillopt 2026-07-20 21:05:09 +01:00
James Davies
a31cc94139 Slim down surface for this integration 2026-07-19 22:37:20 +01:00
James Davies
e34f3c912c Merge branch 'main' of https://github.com/microsoft/SkillOpt into feat/cursor-skillopt-sleep
# Conflicts:
#	plugins/devin/README.md
#	plugins/devin/mcp_server.py
#	tests/test_devin_plugin.py
2026-07-19 21:21:27 +01:00
James Davies
cd5ca48226 Add Cursor SkillOpt-Sleep integration and transcript harvesting. 2026-07-19 21:03:25 +01:00
Yif-Yang
7933f37bf0 test(sleep): assert fractional candidate score 2026-07-18 17:28:22 +00:00
Harshit Nagar
4a4d597527 test(sleep): add fractional degradation gate test for partial held-out regression 2026-07-18 22:24:30 +05:30
Ismar
195d95e00c feat(devin): expose handoff backend in MCP server enum (#3)
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.
2026-07-16 15:20:50 +02:00
Yif-Yang
74ff263608 fix(model): isolate Codex token tracking 2026-07-16 10:02:21 +00:00
Yifan Yang
3e3df8895e Merge pull request #112 from TheGameVIX/agent/codex-exec-optimizer-main
fix(codex): support exec optimizer backend
2026-07-16 18:57:47 +09:00
Yifan Yang
0d8839778c Merge pull request #101 from SparshGarg999/fix/46-windows-support-codex
feat(codex): add Windows support and compatibility for Codex plugin
2026-07-16 18:57:15 +09:00
TheGameVIX
0b94f890a0 fix(codex): support exec optimizer backend 2026-07-15 12:06:46 -04:00
Sparsh :)
7c7fdfcd6c fix(windows): resolve control flow and path quoting in scheduler task execution 2026-07-15 14:54:27 +05:30
Yif-Yang
8b39394c88 fix(sleep): harden OpenAI compatibility boundaries 2026-07-14 09:17:18 +00:00
Yifan Yang
be2184660a Merge pull request #129 from Alphaxalchemy/feat/openai-compatible-endpoints
feat(sleep): support OpenAI-compatible endpoints (DeepSeek, vLLM) in azure_openai backend
2026-07-14 18:10:17 +09:00
Yifan Yang
940c3cd4ec Merge pull request #137 from Yif-Yang/fix/claude-tempdir-cleanup
fix(claude): use cleanup-tolerant temporary directory
2026-07-14 17:50:10 +09:00
Yif-Yang
6a193ffd78 fix(claude): use cleanup-tolerant temporary directory 2026-07-14 08:46:54 +00:00
Yif-Yang
48e4c66827 perf(json): keep array scan linear on malformed output 2026-07-14 08:46:54 +00:00
Yifan Yang
7191f1cb1f Merge pull request #103 from zixuanguo786-ctrl/codex/robust-json-array-extraction
[codex] Harden JSON array extraction
2026-07-14 17:41:52 +09:00
Yifan Yang
7bf9ecbec6 Merge pull request #115 from nankingjing/contrib/add-openai-compatible-backend
feat(model): add generic OpenAI-compatible LLM backend
2026-07-14 17:41:49 +09:00
Yifan Yang
2ffa73410e Merge pull request #105 from zixuanguo786-ctrl/codex/reject-duplicate-searchqa-manifest-ids
[codex] Reject duplicate SearchQA manifest ids
2026-07-14 17:41:45 +09:00
Yifan Yang
c2992b96a6 Merge pull request #104 from zixuanguo786-ctrl/codex/preserve-fractional-hard-score
[codex] Preserve fractional rollout hard scores
2026-07-14 17:41:42 +09:00
Alphaxalchemy
4ff77b71ff fix(sleep): address review — CLI choice, auth guard, provider-neutral 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.
2026-07-14 01:22:19 -06:00
Ziiii
ddc35b339d Fix array extraction after unmatched brace 2026-07-14 09:35:42 +08:00
nankingjing
45ff88a20c test(model): cover OpenAI-compatible backend integration
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-14 09:21:11 +08:00
Yif-Yang
a0b6db59f8 fix(scheduler): preserve existing annealing contract 2026-07-13 16:57:07 +00:00
Yifan Yang
e7665f8f5e Merge pull request #123 from nankingjing/test-scheduler-core
test: add unit tests for skillopt.optimizer.scheduler (edit-budget schedulers)
2026-07-14 01:54:24 +09:00
黄云龙
daf3035429 test(scheduler): update sequence expectation to match consistent endpoint formula
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.
2026-07-14 00:45:22 +08:00
AKhozya
3b0af4668c feat: wire preferences through run cycle into reflect prior 2026-07-13 17:07:16 +01:00
Sparsh :)
79d6117f6f fix: address PR reviews, add scheduler Windows tasks and Pester coverage 2026-07-13 21:20:30 +05:30
Sparsh :)
3c45db3a90 feat(codex): add Windows support and compatibility for Codex plugin 2026-07-13 21:13:15 +05:30
Yifan Yang
25b0f39405 Merge pull request #107 from ichoosetoaccept/fix/plugin-pip-fallback
fix(plugin): fall back to pip/uv-installed skillopt-sleep in run-sleep.sh
2026-07-14 00:36:17 +09:00
Sparsh :)
49a5b617c0 fix(gate): resolve issue #100 (#102) 2026-07-13 01:27:13 +09:00
Chirag Singhal
46e8e800bc fix(qwen): support reasoning-model params (max_completion_tokens, omit temperature) (#128)
The qwen_chat backend (the generic OpenAI-compatible client) hardcoded
max_tokens and always sent temperature, so reasoning models behind
OpenAI-compatible gateways (GPT-5.x, Claude Opus 4.8 via Azure/LiteLLM)
would 400.

- Add opt-in QWEN_CHAT_USE_MAX_COMPLETION_TOKENS (+ role variants) that
  swaps the payload key max_tokens -> max_completion_tokens.
- Treat an explicit empty / none / off temperature as "omit" instead of
  collapsing to the 0.7 default (via _resolve_temperature).
- Thread both through configure_qwen_chat / _update_config.
- Defaults unchanged; fully backward compatible. Adds 6 tests.

Fixes #127

Co-authored-by: Chirag Singhal <chirag127@users.noreply.github.com>
2026-07-13 01:24:40 +09:00
dimitarvdenev
b309723baa feat(sleep): add handoff backend — session-executed model calls, no API subprocess (#125)
Adds --backend handoff: the engine runs all deterministic stages and
outsources attempt/judge/reflect to prompt/answer files an interactive
agent session fills between runs (exit 3 = pending batch, re-run to
resume). Deterministic replay + the prompt-hash answer cache make resume
stateless; sentinel detection aborts any call built from unanswered
output so placeholders never reach scores or staging. Session digests
and mined tasks are pinned per night (secret-redacted) so the sessions
answering prompts cannot shift the task set, and LLM mining is routed
through the same handoff files. Ships a /skillopt-sleep-handoff Claude
Code command that answers each prompt in a fresh-context subagent to
protect the held-out gate.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 01:23:53 +09:00
ClumsyLucid
7df49656d1 fix(skillopt-sleep): surface Claude CLI spawn failures instead of silent zero scores (#126)
* fix(skillopt-sleep): surface Claude CLI spawn failures instead of silent zero scores

In _call and attempt_with_tools, the bare 'except Exception: return ""'
swallows FileNotFoundError (e.g. bare 'claude' on Windows with npm .cmd
shim) and any other spawn failure, returning an empty string that the
trainer treats as a legitimate model response that scores 0.0 everywhere.

Now the exception is caught explicitly: last_call_error is set, a
warning is logged, and the empty-string return is preserved for
backward compatibility of the control flow. This mirrors the pattern
from #92 (codex backend) which fixed the same class of 'dead CLI
masquerades as nothing to learn' bug.

Issue: #121

* test(skillopt-sleep): add tests verifying Claude CLI spawn failures are surfaced

Add two tests to TestClaudeCliBackendBare:
- test_spawn_failure_sets_last_call_error: _call sets last_call_error
  and returns '' when subprocess.run raises FileNotFoundError.
- test_attempt_tools_spawn_failure_sets_last_call_error: same for
  attempt_with_tools.

These prove the fix from the parent commit (surface spawn failures
instead of silently scoring 0) and guard against regressions.
2026-07-13 01:23:10 +09:00
Tanmay Garg
cd8034c2db test(sleep): assert scores and gate_action in verifier tests (closes #94) (#96)
Add explicit assertions for held-out scores and gate actions to the verifier discipline test suite to strengthen its guarantees.

- Assert the concrete held-out baseline and candidate scores in test_gate_rejects_reward_hacking_edit.
- Add test_gate_accepts_beneficial_edit using MockBeneficialBackend to provide a paired case where an edit genuinely improves the held-out slice, expecting accepted=True and gate_action='accept_new_best'.
2026-07-13 01:20:30 +09:00
黄云龙
8687566792 test(gate): add unit tests for evaluation gate decision function (#122) 2026-07-13 01:19:56 +09:00
黄云龙
3c565a7f84 test: add unit tests for skillopt.optimizer.scheduler 2026-07-11 15:06:11 +08:00
Ismar
ce55241a89 fix(plugin): fall back to pip/uv-installed skillopt-sleep in run-sleep.sh
The Claude Code and Codex plugin shells' runner (run-sleep.sh) only
resolved the engine by searching for a skillopt_sleep/ source directory
on disk. After v0.2.0 shipped the engine on PyPI (skillopt-sleep CLI),
the plugins still errored for users who installed via pip/uv without
cloning the repo — even though the error message said "pip install
skillopt" would work.

Add two fallbacks before the error:
  1. skillopt-sleep CLI on PATH (covers uv tool install, pipx, pip install)
  2. python -m skillopt_sleep when importable (covers pip install into
     the active Python)

Fallback 1 is checked before fallback 2 because uv tool install / pipx
isolate the package from the system Python's import path, so the import
check would fail even though the CLI is available.

The existing source-checkout resolution path is unchanged — repo-clone
users keep working as before. The fix lands in both plugins/run-sleep.sh
(shared, used by Codex) and plugins/claude-code/scripts/run-sleep.sh
(bundled copy, byte-identical, used by the Claude Code marketplace
install which fetches only the plugins/claude-code/ subtree).
2026-07-06 15:25:38 +02:00
Ziiii
08916747ef Reject overlapping SearchQA manifest ids
Runnable SearchQA splits should remain disjoint. A duplicate manifest id across train, val, or test previously collapsed into the wanted-id set and reused the same row in multiple output splits without warning.

Constraint: Preserve manifest order and output schema for valid manifests.

Rejected: Deduplicate automatically | hiding split overlap would make evaluation contamination harder to notice.

Confidence: high

Scope-risk: narrow

Reversibility: clean

Directive: Fail fast on split-manifest integrity problems instead of repairing them silently.

Tested: uv run --with pytest pytest tests/test_materialize_searchqa.py -q

Tested: uv run --with ruff ruff check scripts/materialize_searchqa.py tests/test_materialize_searchqa.py

Not-tested: Loading the live Hugging Face dataset.
2026-07-06 15:42:15 +08:00
Ziiii
0c30b778fb Preserve continuous rollout hard scores
Rollout hard scores can be continuous when smoothed rewards are used. Converting the field through int() turned values like 0.75 into 0, which loses signal before scoring and serialization.

Constraint: Keep the existing RolloutResult dictionary shape unchanged.

Rejected: Clamp hard scores to 0 or 1 | contradicts existing continuous-score support in compute_score and sleep replay types.

Confidence: high

Scope-risk: narrow

Reversibility: clean

Directive: Treat hard as numeric reward data, not only a binary label.

Tested: uv run --with pytest pytest tests/test_types.py tests/test_scoring.py -q

Tested: uv run --with ruff ruff check skillopt/types.py tests/test_types.py

Not-tested: Full benchmark rollouts.
2026-07-06 15:42:07 +08:00
Ziiii
bf85781ffb Avoid ambiguous JSON array extraction
LLM responses can include bracketed prose before the actual JSON array. The old greedy regex spanned from the first '[' to the last ']', causing valid single-array answers to be dropped and making multiple arrays indistinguishable.

Constraint: Keep object extraction behavior unchanged.

Rejected: Return first parseable array | silently guesses when a response has multiple valid arrays.

Confidence: high

Scope-risk: narrow

Reversibility: clean

Directive: Keep array extraction conservative when more than one valid top-level array is present.

Tested: uv run --with pytest pytest tests/test_json_utils.py -q

Tested: uv run --with ruff ruff check skillopt/utils/json_utils.py tests/test_json_utils.py

Not-tested: Full benchmark rollouts.
2026-07-06 15:42:01 +08:00
Yif Yang
5487e2c426 fix(skillopt-sleep): redact secrets before persisting cycle diagnostics
PR #92 added a per-cycle diagnostics.json that surfaces backend stderr,
optimizer replies, and task responses so a 0.0 night is self-diagnosing.
Those free-text fields can carry credentials (e.g. a codex 401 stderr dump
containing an auth token), so persisting them verbatim was a new on-disk
leak surface.

- Add a shared redact_secrets() in staging.py and route diagnostics.json's
  call_error / reflect_raw_head / holdout_detail through it before writing.
- Redact the codex and Claude auth-error log lines too (a secondary sink
  when a file log handler is attached); last_call_error stays raw in memory
  so _AUTH_MARKERS matching is unaffected.
- Centralize _SECRET_PATTERNS in staging.py (harvest_codex now reuses them)
  and extend coverage to AWS / GitHub / Slack / Google / JWT token shapes.
- Tests: secret-shape coverage, private-key blocks, recursive/scalar
  passthrough, no over-redaction of plain prose, fail-fast auth-error log
  redaction, and an end-to-end check that diagnostics.json has no secret.

Observability-only; the gate and learning algorithm are unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-30 19:47:36 +00:00
Yifan Yang
b9142bad24 fix(skillopt-sleep): surface codex auth/model/version failures instead of silently scoring 0 (#92)
Splits CodexCliBackend._call into _call_once + a retry wrapper so transient empties/timeouts are retried instead of silently scored 0, and fails fast on fatal auth/model/version errors (401, refresh_token_reused, token_expired, ChatGPT-account-unsupported, newer-Codex-required). On non-zero exit the CLI error text is surfaced via last_call_error instead of being returned as a model response. Adds per-cycle diagnostics.json (observability only; gate and learning algorithm unchanged) so a 0.0 night self-explains.
2026-07-01 03:20:08 +08:00