Repository navigation
sidecall: read the result event out of a verbose Claude Code reply - #141
Closed
fchengyan (fcy222fcy) wants to merge 1 commit into
Closed
fchengyan (fcy222fcy) wants to merge 1 commit into
fchengyan (fcy222fcy) wants to merge 1 commit into
Conversation
…icrosoft#131) With "verbose": true in the user's Claude Code settings, -p --output-format json prints a JSON array of stream events instead of the bare result object, so claude_call's data.get("result") raised AttributeError ('list' object has no attribute 'get'). The micro-skills proposer called its runner unguarded, so the same exception aborted the whole fold: the session stayed pending and was re-folded, with another paid call, on a later eligible tick. - claude_call now parses either shape: a list's last type=="result" event, or the bare object as before (microsoft#131) - Distiller._maybe_propose guards its runner like the loop guard's judge does: a failed side call skips the proposal and backs off one cadence instead of aborting the fold (microsoft#131)
Author
|
@microsoft-github-policy-service agree |
Collaborator
|
Thanks for this, and for the clear red/green write-up. #134 fixes #131 the same way and also logs the failed proposer call to errors.log, so I’m merging that one and closing this as a duplicate. Your handling of a non-object JSON reply (e.g. null) is a nice touch that #134 doesn’t have. A small follow-up PR on top of #134 for that case would be welcome. |
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.
Summary
Fixes #131. With
"verbose": truein the user's Claude Code settings, every Claude Code side call failed, and the micro-skills proposer's unguarded runner call aborted the whole fold.Two defects, both in the #131 report:
claude_callmis-parsed the reply. Under-p --output-format json, a verbose Claude Code prints a JSON array of stream events (system,assistant, ...,result), not the bare result object.json.loadsthendata.get("result")raisedAttributeError: 'list' object has no attribute 'get'.Distiller._maybe_proposecalled its runner unguarded. Unlike the loop guard's judge (loopguard/judge.pycatches runner exceptions and recordsrunner-error:...), the proposer let the exception escape, so the fold failed: the session stayed pending, got no ledger row, and was re-folded — with another paid Haiku call — on a later eligible SessionStart event.What changed
tokeneconomizer/plugin/sidecall.py— new_claude_json_result(stdout)normalizes what the CLI printed: a list's lasttype == "result"event, the bare object as before, or{}.claude_calland nothing else changes shape: the usage/modelUsage accounting and the_no_replypath are untouched.tokeneconomizer/microskills/distiller.py—_maybe_proposeguards its runner like the judge does: a failed side call skips the proposal instead of aborting the fold, and backs off one cadence (last_propose = now) so a broken runner is not paid again on every tick.tests/test_sidecall_verbose.py— three regression tests (below).I went with shape-accepting rather than the report's
--settings '{"verbose":false}'suggestion: it needs no capability probe of--settings, and it keeps working for a CLI that prints the array for any other reason.Verification
Red/green with the subprocess faked the way
test_live_core.pyfakes it (the reporter's real-CLI repro is not available on this machine):resultevent → before:AttributeError: 'list' object has no attribute 'get'atsidecall.py:235; after: returns("OK", eff)with usage charged.resultevent → before: sameAttributeError; after: comes back empty through the_no_replypath._maybe_propose→ before: the exception escaped and aborted the fold; after: the proposal is skipped andlast_proposebacks off.Reverse control:
git stashof the two source files (tests kept) turns all three red; restoring turns them green. Full offline suite (python -m pytest tests -q) is green on Python 3.11 / Windows, includingtest_live_core.pyandtest_live_repos.py.AI disclosure
This fix was authored with AI assistance (Claude agent, at the direction of fcy222fcy).