feat(sleep): add Pi transcript source and CLI backend - #83
Conversation
Adds `--source pi` to SkillOpt-Sleep so it can harvest sessions from the
pi coding agent (`~/.pi/agent/sessions/<slug>/*.jsonl`), on par with the
existing claude/codex sources.
pi schema notes (verified against real transcripts):
- entry discriminator is `type`; cwd lives on the single `session` entry
- conversational turns are `type:"message"` with `message.role` in
{user, assistant, toolResult}
- content blocks use `toolCall` (not Claude's `tool_use`) and carry `name`;
`thinking` blocks are private reasoning and are skipped
- toolResult messages carry `isError` + `toolName`, a per-call
success/failure signal surfaced as a `neg:tool_error:<tool>` feedback
signal — the checkable outcome the gate thrives on
Changes:
- skillopt_sleep/harvest_pi.py: new harvester (digest_pi_session + harvest_pi),
stdlib-only, reuses shared helpers from harvest.py
- skillopt_sleep/config.py: `pi_home` default (~/.pi) + `pi_sessions_dir` property
- skillopt_sleep/harvest_sources.py: `pi` source + `auto` fallback
- skillopt_sleep/__main__.py: `--source pi` choice + `--pi-home` flag
- tests/test_harvest_pi.py: field extraction, scope filter, secret redaction
Verified end-to-end against real local pi sessions (Korean + English, tool
errors, thinking blocks correctly excluded).
Follow-up to PR feedback: pi's `isError` on toolResult records only whether that single tool invocation failed mechanically. In agentic coding, intermediate tool errors are normal and frequently followed by recovery and a successful final result. Surfacing every such error as `neg:tool_error` would mislabel successful sessions as failures (the verifying session that produced `neg:tool_error:bash, neg:tool_error:edit` was in fact a successful recovered session) and poison the miner's task-outcome labels. Task outcome should be inferred from the user's judgment of the final result (the lexical feedback phrases), not from transient tool mechanics. - harvest_pi.py: drop the `neg:tool_error` emission; keep toolName extraction (still a useful corroborating tool-name source). - test_harvest_pi.py: assert isError is NOT surfaced as feedback.
|
@microsoft-github-policy-service agree |
Companion to `--source pi`: a `PiCliBackend` that drives the pi coding agent's headless mode (`pi -p`) for replay. pi speaks the open Agent Skills standard and supports `-p`/`--print`, so it slots in alongside the existing claude/codex/copilot CLI backends — and crucially, the replay model is whatever the user has configured in pi (e.g. `zai/glm-5.2`), keeping source and backend on the same agent instead of forcing Claude/Codex. Changes: - skillopt_sleep/backend.py: `PiCliBackend(CliBackend)` implementing `_call` via `pi -p --no-session --no-tools --no-skills --no-context-files --no-extensions [--model M] <prompt>` from a clean temp cwd. Auth/config errors detected and surfaced (mirrors the Claude backend). Registered in `get_backend` with aliases (pi, pi_cli, pi_coding_agent) + `pi_path` arg. - skillopt_sleep/cycle.py + config.py: thread `pi_path` through config. - skillopt_sleep/__main__.py: `--backend pi` choice + `--pi-path` flag. - tests/test_backend_pi.py: alias resolution, env-default model, isolated command construction, auth-error detection. Verified end-to-end: `PiCliBackend(model='zai/glm-5.2')._call(...)` invokes `pi -p` and returns the real model response in ~5s (not mock). `ruff` clean on touched files; full suite passes (72 tests).
|
Hi @auspic7 — thanks for this, it's a clean addition. This PR has been in draft for a while; is it ready to merge? I reviewed and tested it locally (pi harvester + backend tests pass, no regressions). One small thing worth addressing before/after merge: in |
|
Hi @auspic7 — thanks, |
|
Hi @auspic7 — friendly status check on this one. The CLA is all set, but the PR is still in draft and currently has merge conflicts. When you have a moment, could you rebase onto the latest main to resolve the conflicts and mark the PR as Ready for review? Once that is done, we will take another pass promptly. Thanks! |
There was a problem hiding this comment.
Pull request overview
This PR adds an explicit Pi integration path to SkillOpt-Sleep, enabling both (1) harvesting Pi session transcripts from the local ~/.pi/agent/sessions tree and (2) running the Sleep cycle through a locally installed/authenticated Pi CLI backend, while keeping source selection (--source) and backend selection (--backend) independent and preserving existing --source auto precedence.
Changes:
- Added a Pi transcript harvester (
--source pi) with schema validation, active-branch selection for v2/v3 sessions, and secret-shaped string redaction. - Added a Pi CLI backend (
--backend pi) that runs in print mode with strong isolation flags and offline startup env settings. - Expanded CLI/config/routing, OpenClaw plugin wiring, and tests/docs to cover Pi paths end-to-end.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/test_plugin_sync.py | Extends plugin sync coverage to ensure OpenClaw wrapper matches updated shared backend factory signature (including Pi params). |
| tests/test_pi_integration.py | Adds CLI/config and harvest routing tests ensuring --source pi is explicit and --source auto does not select Pi. |
| tests/test_model_change_warning.py | Ensures model-key construction forwards pi_path into backend build for cache-key correctness. |
| tests/test_harvest_pi.py | Comprehensive unit coverage for Pi session digestion/validation, branch selection, and redaction behavior. |
| tests/test_backend_pi.py | Unit tests for Pi CLI backend invocation, isolation flags, error handling, caching semantics, and token accounting. |
| skillopt_sleep/harvest_sources.py | Adds pi as an explicit transcript source routed to the new harvester. |
| skillopt_sleep/harvest_pi.py | Implements Pi JSONL reading, schema checks, active-branch extraction, normalization into SessionDigest, and directory walking harvest. |
| skillopt_sleep/cycle.py | Includes pi_path in backend construction inputs for stable model-keying and runtime wiring. |
| skillopt_sleep/config.py | Adds pi_home, pi_path, and a derived pi_sessions_dir to configuration defaults/accessors. |
| skillopt_sleep/backend.py | Introduces PiCliBackend, adds Pi aliases to get_backend, and wires pi_path through build_backend (single + dual backend). |
| skillopt_sleep/main.py | Adds CLI flags --pi-home / --pi-path and extends --backend / --source choices to include pi. |
| plugins/README.md | Documents Pi source/backend behavior, privacy boundary, and CLI flags in the plugin integration README. |
| plugins/openclaw/skillopt_sleep_openclaw.py | Refactors reference-answer rubric formatting for readability/maintainability. |
| plugins/openclaw/run_sleep.py | Updates OpenClaw’s backend factory shim to accept/forward the expanded shared signature including Pi params. |
| docs/sleep/README.md | Adds Pi source/backend documentation and updates high-level pipeline description to include Pi. |
| docs/reference/cli.md | Updates CLI reference to include Pi flags and clarifies network/no-network backend boundary language. |
| docs/guide/installation.md | Adds optional Pi CLI installation guidance and clarifies that Pi harvesting does not require the CLI. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Thanks @brandon and @auspic7 for bringing the Pi integration forward, including the follow-up CLI failure handling. Since this PR remained in draft and had diverged from One important final behavior is that Pi remains explicit-only: Maintainer validation completed successfully:
We are marking this ready and proceeding with a normal merge commit so the original contribution history remains intact. |
Yif-Yang
left a comment
There was a problem hiding this comment.
Maintainer integration, full-suite validation, Pi CLI smoke testing, and independent security/correctness reviews are complete. No merge blocker remains.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.
Suppressed comments (1)
tests/test_harvest_pi.py:14
- In this helper you write JSONL records without specifying an encoding. Most other tests in this repo use
encoding="utf-8"for text writes, and leaving it implicit can cause platform-dependent behavior (e.g., Windows default code pages) if Pi sessions contain non-ASCII text.
with open(p, "w") as f:
Summary
Adds explicit Pi integration to SkillOpt-Sleep:
--source piharvests local Pi JSONL sessions from~/.pi/agent/sessions.--backend piruns mining, replay, judging, and reflection through a locally installed, authenticated Pi CLI.Pi is opt-in.
--source autokeeps the existing Codex-then-Claude precedence and does not select Pi.Original contribution
The original branch introduced:
toolResult.isErrorvalues from task-outcome feedback.The original PR reports:
ruff checkpassing on the touched files.54 passed, 1 skippedfor the initial harvester and Sleep tests.zai/glm-5.2.These are the original contributors' reported validations; maintainer validation is listed separately below.
Maintainer integration and hardening
Because the branch had become stale and conflicted with current
main, maintainers integrated it without rewriting the original commits and added:--source auto.PI_OFFLINE=1to disable Pi startup update/package/telemetry traffic while still allowing the configured model-provider request.cwdboundary.Privacy boundary
Pi transcript harvesting is local and read-only. When a real backend is selected, transcript-derived prompts are sent to that backend's configured provider.
Known secret-shaped strings in retained message text are redacted on a best-effort basis. The absolute project
cwdis retained for scope filtering and may appear in miner prompts; it is not covered by message-text redaction.Validation
Maintainer-performed validation:
76 passed in 1.05sacross the Pi backend, harvester, integration, model-warning, and plugin-sync tests.PI_OFFLINE=1still reached/v1/chat/completionsand returned the expected response.664 passed, 6 skipped, 130 subtests passed.compileall, CLI help, andgit diff --checkpassed.