Repository navigation
io-cli 0.36.0 - #94
Merged
Merged
Conversation
…as unknown io-harness 0.76.0 makes Usage::cache_write_tokens an Option<u64>. That is the shape this module's own first honesty rule has always wanted — src/cost.rs has said since 0.13.0 that a token count a provider reported no usage for is unknown, never zero — and it is not a hypothetical distinction: every OpenRouter call reports None, and OpenRouter is where this product's evidence is taken. unwrap_or(0) would have compiled perfectly and put a fabricated figure on the page an operator reads to find out what a turn cost. Instead: - add_reported folds two counts. Two silences stay a silence; one silence beside a number keeps the number, because a turn that reported 1,000 writes and a turn that reported nothing together wrote at least 1,000. The residual — a mixed sum is a floor rather than a total — is stated in the function's own doc rather than hidden, matching how this page already treats an unpriced model's money. - The remainder inherits the silence. "of which fresh" is the prompt less both cached parts, so an unreported write makes it unknown too. - The cache block is drawn when reads are non-zero or writes are a reported non-zero, so a provider reporting reads and no write count still shows the written row as unknown. An absent row reads as zero. src/ compiled clean on the pin; only tests/cost.rs broke, at exactly the sites the pre-code audit named. tests/stats.rs and tests/status.rs were predicted safe because they build Usage through ..Default::default(), and both compiled untouched. tests/cost.rs 12 passed / 0 failed, up from 10. Both new arms carry their sabotage in the doc comment.
Task: US-IO-CLI-0.36.0-T02
Task: US-IO-CLI-0.36.0-T03
Task: US-IO-CLI-0.36.0-T05
Task: US-IO-CLI-0.36.0-T04
Task: US-IO-CLI-0.36.0-T06
Task: US-IO-CLI-0.36.0-T07
Task: US-IO-CLI-0.36.0-T08
Task: US-IO-CLI-0.36.0-T09
…t is not sent The adversarial review found four High behind a fully green suite. Three of the ACP ones shared a root cause. The serve loop awaited handler.handle() inside a tokio::select! arm. For a session/prompt that call IS the whole turn, so the outbound channel was not polled again until the turn returned: every session/update queued and the client received the entire conversation AFTER being told the turn had ended. The guide promises "the answer, streamed as the provider returns it". `biased` could not help, because the loop was not at the select point to be biased about. The writer now runs on its own task and owns the writer outright, so a notification sent from inside a running turn is written while the turn is still running. No Mutex: a lock held across an await on a pipe a slow client is not draining is a deadlock with no error message. Verified against a real provider — message chunks and a thought chunk arrive before the result. The suite could not see it. Nothing drove serve_with with a live channel, and the loop test's updates came from the handler's return value, which is a path the real handler never uses. Both loop tests now run over a duplex pipe, and a new test asserts the wire ORDER across a handler that sends while it works. Two more from the same review: - ApprovalDecided reported in_progress for every decision, discarding the approve/deny/defer the harness carries. Since the ACP approver always denies, every grey-tier action left a cell spinning for ever on a call that would never complete. - The refusal notification put the target PATH in toolCallId, so it named a cell that had never been announced and a conforming client had nothing to apply it to. It is built from the run and step now, as every tool_call frame is. And the false claims. Five documents said io raises session/request_permission. It does not: it sends a session/update refusal. Raising the request means awaiting the answer, and routing that back into the run is not wired — a prompt whose outcome is ignored is worse than no prompt. CONTRACT.md, the guide, the CHANGELOG, --help and three comments now say what the code does. The model is told the interface could not route the approval, not that the operator denied it, because the operator was never asked. Separately, on the pin side: a mixed cache-write fold drew "of which fresh" as an exact number when it is a ceiling. add_reported folds one reporting call and one silent one to Some(n), and n is a floor; subtracting a floor from the prompt gives an upper bound, too large by exactly the amount nobody measured. That is verbatim the failure the adjacent comment says must not happen — the guard only distinguished "no call reported" from "some call reported". Total gains unreported_writes, the written row reads "1.0k or more", and fresh reads unknown. Reachable in practice: openai_wire reports no cache-write count and Anthropic reports one only where a cache was created. 104 binaries / 1,896 passed / 0 failed / 37 ignored. fmt, clippy -D warnings and doctests clean.
The adapter reads newline-delimited JSON-RPC off stdin and writes frames to stdout, which is AsyncBufReadExt::read_line over tokio::io::stdin(). Features of a name already in the tree rather than a name of its own, so the direct dependency set stays at ten and tests/dependencies.rs is untouched. The argument for hand-writing the wire instead of taking agent-client-protocol lives beside the feature list: that crate's graph brings a second async executor family — async-io, async-process, async-task, blocking, polling — with its stdio transport putting blocking::Unblock over the real stdin and stdout. src/stdin.rs exists because of what a second owner of stdin cost in 0.13.1.
io-cli 0.36.0 — the Agent Client Protocol adapter, and the io-harness 0.76.0 pin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The release PR for 0.36.0. Everything in it is PR #93, which merged into
developwith 8/8 green on all three platforms;git diff --quiet feat/0.36.0 developconfirms nothing else landed ondevelopwhile the release was in flight.io is reachable from an editor.
io acpserves the Agent Client Protocol on stdin and stdout. The direct dependency set is still exactly ten names — the wire is written here rather than taken, because the official crate's graph brings a second async executor family over the real stdin.The io-harness pin moves 0.74 → 0.76.0.
The adversarial review found four High behind a fully green suite, the fifteenth consecutive release: nothing streamed,
session/request_permissionwas never sent while six documents said it was,session/cancelwas unreachable during a turn, and/costdrew a ceiling as an exact fact. The first and last are fixed; the middle two are shipped as stated limitations, on thefallback_scopethis release declared in advance.104 binaries / 1,896 passed / 0 failed / 37 ignored. fmt, clippy
-D warnings, doctests andultraship validate(113 checks) all clean. Live gate run against a real provider through the built binary.