Repository navigation
Drive whip v1.0.0 through its SDK behind the harness seam - #61
samheutmaker wants to merge 6 commits into
Conversation
Loupe now drives `whipcode`, the binary whip v1.0.0 ships: the pinned self-install downloads `whipcode-<os>-<arch>` from that tag into ~/.loupe/bin/whipcode, `whipcode` on PATH is used as is (every v1 binary is whipcode, so the v0 identity check goes), and LOUPE_WHIP_BIN overrides both. The workflows install the same tag explicitly. The SDK that talks to that daemon is vendored under vendor/@Whip from the v1.0.0 tag (protocol 6.8), refreshed with `task vendor:whip`; VERSION records the tag, commit, and wire protocol. Nothing uses it yet; the next commit moves the harness onto it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The harness package keeps its name and its `Harness` seam, with one
implementation: `whipHarness(client)`. `review(ctx)` now names which loupe
agent to run (reviewer, verifier, chat, fixer) and the output contract its
final message must match, builds that agent definition, serves it from this
process, runs one turn on a session pinned to it on the shared daemon, and
returns `{ text, output }`: the final message and the value the daemon
validated against the contract. No subprocess, no NDJSON scraping; typed turn
events feed the run log and, through `turnEventToTrace`, the same trace
pipeline the step summary renders. Claude, codex, the registry, the cache-key
retry, and the whip binary identity check go.
Core's two call sites (the review with its headless fallback, and verify)
pass `agent` and `output`; `parseReviewOutput` and `parseVerification` read
the validated output, or the final text when the turn cap answered past the
check, so salvage and the malformed counts keep working. Reviewers are
read-only whip agents with the `files` module (no shell), so the prompt's
tool hints say list/read/search instead of ls/cat/grep and the sentence
about subagents goes. The whip block's provider is named on every session
because a desktop daemon's default provider may not carry the model, and
`reasoning` rides on the session (`session.effort`) since one daemon now
serves every reviewer.
The action brings whip up once per process (`resolveHarness`: credential
chain, `ensureDaemon`, `connect`) and lets it go at exit (`releaseWhip`);
concurrent reviewers share that daemon and client. `--harness` is gone;
`harness: "whip"` in a config and `LOUPE_HARNESS=whip` are still accepted,
anything else is an error.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
README, architecture, configuration, the Action and CLI guides, credentials, review traces, the how-it-works pages, and the example workflow describe one harness: the pinned whipcode install, the daemon loupe starts or attaches to, the SDK path, the output contract the daemon enforces, and reasoning set on the session. Claude and codex, the subprocess, `--harness`, and the panel paragraph are gone; main's diagrams and the sections on ensemble, dedup, the comment cap, the publish gate, and status routing stay as they were. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The first dry run on the desktop daemon failed both the agentic review and its headless fallback with `session.effort failed: glm-5.3 does not support effort "medium"`: the daemon checks the effort against the model's levels, where `whip run` had quietly applied its model-aware default. The session now keeps that default and logs what was asked for and why it was not applied; the reasoning note in the prompt still applies. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The self-review ran `context-labs/loupe@main`, so a PR that changes loupe was reviewed by the code it replaces. Using the checkout makes each PR's self-review a run of its own code, including the whip install and daemon bring-up it ships with. On main the two are the same thing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The CI path failed every turn within seconds: `output_invalid: the message is empty`, on the agentic run and its fallback alike. A daemon started from the materialized home has no model catalog, because the daemon only fetches one when a client asks (the desktop app does that when a provider is set up), and without it a model's limits collapse to a one-token output cap. glm-5.3 spends that token on reasoning and returns no content. After connecting, loupe now asks the daemon for the whip block's provider catalog (`provider.catalogs`), which fetches a missing or stale one and is a no-op on a daemon that already has it. Discovery failing is a warning that names the consequence; the turn's own failure says the rest. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
This PR is too large for Bugbot to review. It changes 113,174 lines and 4,065,352 characters. Split the change into smaller pull requests to get a review. |
🔍 Loupe reviewcode✅ no issues · 19 files Ports loupe from driving the Run details
Last reviewed commit: docs✅ no issues · 33 files This PR replaces the multi-harness subprocess runner (whip v0.6.5 Run details
Last reviewed commit: Use |
Why
Whip v1.0.0 renamed its binary to
whipcodeand ships the TypeScript SDK; main pins whip v0.6.5 and driveswhip runas a subprocess, scraping its NDJSON. This re-ports the SDK migration (feature/whip-sdk) onto main as a few commits, keeping everything main does today — ensemble legs and degradation, cross-reviewer dedup, the comment cap, the publish gate, quota and rate-limit routing, review traces, call-site discovery, salvage, incremental review, skills,@loupechat and fix — and changing only how a turn runs. Plan and implementation record: whip.ai-docs/plans/loupe-whip-v1/PLAN.md.What changes
vendor/@whip, protocol 6.8, refreshed withtask vendor:whip). The pinned self-install downloadswhipcode-<os>-<arch>into~/.loupe/bin/whipcode;whipcodeon PATH is used as is;LOUPE_WHIP_BINoverrides. Both workflows install v1.0.0 explicitly.packages/harnesskeeps its name and itsHarnessseam with one implementation,whipHarness(client).review(ctx)names the loupe agent (reviewer, verifier, chat, fixer) and the output contract, builds the definition, serves it from this process, runs one turn on a session pinned to it, and returns{ text, output }— the final message and the value the daemon validated against the contract. Typed turn events feed the run log and the existing trace pipeline (turnEventToTrace). Reviewers are read-only whip agents (context+files, no shell); the whip block's provider is named on every session; reasoning is set per session. One daemon and one client per process, shared by concurrent reviewers, released at exit. Claude, codex, the registry, the cache-key retry, and the binary identity check are gone.harness: "whip"in a config andLOUPE_HARNESS=whipare still accepted; anything else is an error.uses: ./), so this PR is reviewed by its own code, whip install and daemon bring-up included.medium;whip runapplied its default silently), and loupe asks the daemon to discover the provider's models after bringing it up (below).Validation
task check: 44 files, 522 tests. Main'srun-review(38),retry,orchestrate,respond,config,errors, and actiontracetests are kept; the fake harness returns{ text, output }. The runner itself is tested against@whip/sdk/testing's scripted daemon.context-labs/loupe#15against a whipcode 1.0.0 daemon (glm-5.3 on inference.net): both reviewers agentic on one daemon; a forced headless fallback with agentic verify; chat; a fixer turn on a scratch clone where the hook deniedgit commit; three loupe processes on one daemon at once.INFERENCE_API_KEYset → throwawayWHIPCODE_HOME, dedicated daemon): both reviewers agentic, the docs reviewer's two findings kept by agentic verify, the daemon stopped at exit, the desktop daemon untouched.Notes
output_invalid: the message is empty: the daemon only fetches a provider's catalog when a client asks (the desktop app does), and without it a model's limits collapse to a one-token output cap. Loupe now callsprovider.catalogsfor the whip block's provider after connecting; a no-op on a daemon that already has one. Whip follow-up: discover on demand inresolveRuntimeModel(cmd/whip/daemon.go) or refuse a 1-token cap.session.effort) rather thandefaultEffortin a per-call home, since one daemon serves every reviewer.costUsdon the turn (the SDK forwardsstream.accountingas a raw event and none reached the turn window); large inputs arrive as context handles the model reads and then mentions in its summary.🤖 Generated with Claude Code