Agent-ergonomics fixes from CLI transcript mining: py3.12 sandbox, list_instances, usage-on-error, JSON query-raw errors - #328
Open
qu0b wants to merge 9 commits into
Open
Agent-ergonomics fixes from CLI transcript mining: py3.12 sandbox, list_instances, usage-on-error, JSON query-raw errors#328qu0b wants to merge 9 commits into
qu0b wants to merge 9 commits into
Conversation
LLM-generated code routinely nests same-quote strings and backslashes inside f-string expressions, which is a SyntaxError on 3.11. Lock recompiled with the same pinned uv; resolution is unchanged.
Instance labels were not enumerable from the sandbox: models guess ethnode.list_instances(network) and fail. Dora already tracks every node, and its client_name is exactly the ethnode instance label, so expose /api/v1/clients/consensus as dora.get_clients and derive ethnode.list_instances (name + online/offline status) from it.
- unknown-flag and arg-count errors now carry the command's usage line
(SilenceUsage previously left them with no correction path)
- panda execute gains -c as --code shorthand
- query-raw failures emit {"error": ...} on stdout and suppress the
stderr duplicate, so 2>&1 JSON pipelines surface the real error
instead of a JSONDecodeError; its update notice is skipped for the
same reason. Error printing moves from cobra into Execute, which
knows which failures were already reported.
Contributor
🐼 Smoke eval —
|
| question | result | tokens | tools |
|---|---|---|---|
forky_node_coverage |
✅ | 16,491 | 7 |
tracoor_node_coverage |
✅ | 16,661 | 6 |
mainnet_block_arrival_p50 |
✅ | 15,725 | 7 |
list_datasources |
✅ | 13,139 | 2 |
block_count_24h |
✅ | 20,410 | 11 |
missed_slots_24h |
✅ | 25,047 | 20 |
chartkit_default_arrival_distribution |
✅ | 34,143 | 19 |
storage_upload_session_scoped |
✅ | 17,687 | 11 |
🔭 Langfuse traces (8 runs; ⚠️ = failed)
The report walks this branch's commits against the master baseline and the most recent release. A self-contained copy is in the run's eval-smoke-* artifact.
A JSON-RPC error object rides back on a healthy node connection: the node processed and rejected the request (unsupported method, bad params, node-side limits, reverts). Returning 502 made deterministic failures look transient — transcripts show agents retrying -32601 method-not-found hours later and misreading capability gaps as outages. Return 400 and append the error's data payload, which often carries the actual answer (e.g. a revert reason).
On 2026-07-08 the embedding upstream hung and every panda search blocked for the full 2-minute batch timeout before failing. Single-item embeds (the interactive search shape) now get a 15s deadline; batch calls get 130s, deliberately outlasting the proxy's 2-minute upstream timeout so its specific error surfaces instead of a generic client timeout. Search failures caused by an unreachable embedding upstream or a warming index now return 503 instead of 400 — they are retryable service conditions, not query errors.
JSON-RPC rejections get a do-not-retry hint (method-not-found is a client capability gap, keyed on the message so old servers' 502 wrapping benefits too); embed-upstream and index-warming search failures get an explicit retry-shortly hint instead of the generic status hint.
Root-level SilenceErrors inverted error printing for the whole tree to serve one command: every other entry point executing rootCmd would lose output, and Execute had to mirror cobra's printing forever (it already dropped the unknown-command usage line). Instead, query-raw's RunE sets SilenceErrors on itself only after the stdout JSON error is written — flag and arg errors return before RunE and stay loud, and cobra's own printing is restored everywhere else.
…potent usage wrap - embed timeouts came from item count, so a warm index rebuild embedding exactly one new document was clamped to the 15s query deadline. The deadline is now handed down from the public entry point (Embed = query, EmbedBatch/EmbedQueryBatch = build); a regression test pins that a one-item build honors the deadline it was given. - cap the JSON-RPC error data payload at 512 bytes; some clients return whole traces and an error message is not a data channel. - attachUsageToArgErrors is not idempotent, so guard it with sync.Once against a second Execute() in-process. - ethnode.list_instances explains the Dora dependency when the explorer is unavailable instead of surfacing a bare Dora error.
Two leftovers fitted to the sampled transcripts rather than the failure: - error-as-JSON and update-notice suppression keyed on the query-raw command name, but the failure is 'stdout is JSON and stderr gets merged into the pipe' — true of every command run with -o json, which the same transcripts also do. Replaced with one machine-output mode (isJSON() or an always-JSON command): stdout carries exactly one JSON document, stderr stays empty, exit code conveys failure. query-raw's per-command printing and SilenceErrors hack are gone. - searchErrorStatus matched the two error strings seen in the incident and missed their sibling, '<x> search index not available' (index never activated), which kept returning 400. Filter-value rejections stay 400. Also fixes two pre-existing machine-honesty bugs the mode change makes safe: 'panda execute --json' and 'panda build --json' exited 0 when the execution or build had failed, unlike their text paths.
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.
Mined every Claude Code session that drove the panda CLI (June 12 – July 15: 777 invocations, 43 hard failures) and fixed the failure classes that repeatedly burned real devnet investigations. Each fix is verified against the exact command that failed in the transcripts.
sandbox: Python 3.11 → 3.12 (PEP 701)
LLM-generated code routinely nests same-quote strings and backslashes inside f-string expressions — a
SyntaxErroron 3.11, legal on 3.12. Base image bumped to pinnedpython:3.12-slim; the hash lock was recompiled with the same pinned uv (0.11.17) and resolution is unchanged (header-only diff). Verified: image builds,ethpandaops/pandasimport, transcript-failing f-strings parse on 3.12.13.dora + ethnode:
get_clients/list_instancesModels guess
ethnode.list_instances(network)afterlist_networks()and hit an ImportError; instance labels were documented as non-enumerable. They are enumerable: Dora's/api/v1/clients/consensusclient_nameis exactly the ethnode instance label (verified against live hoodi). Newdora.get_clientsserver op + Python wrapper, andethnode.list_instances(network)returns sorted{name, status}— status distinguishes online/offline nodes for free. Covered by two new server tests.cli: stop making agents guess syntax
SilenceUsageleft flag typos as a bareError: unknown flag: --networkwith no correction path — transcripts show 6+ guessed-flag failures (--network,--like,--database,--datasource,-c, arg-count misses). Now:--helppointer (SetFlagErrorFunc)panda execute -cworks as shorthand for--codecli: machine output mode — JSON in, JSON out
The single most frequent wasted-iteration pattern (~15 occurrences):
panda clickhouse query-raw ... 2>&1 | python3 json.loadfails, the JSONDecodeError masks the real ClickHouse error, and the agent retries blind. The general condition is stdout is a JSON document and the consumer merges stderr into the pipe — which the transcripts also do with-o jsonon other commands.So the rule is per-run, not per-command: when output is JSON (
-o json/--json, or an always-JSON command like query-raw), the CLI owns error rendering — stdout carries exactly one JSON document, stderr stays empty, and the exit code conveys failure. Update notices are suppressed in that mode too (they broke even successful pipelines). Human text mode is untouched: cobra still printsError: ...to stderr.This also fixes two pre-existing machine-honesty bugs that the mode change makes safe to correct:
panda execute --jsonandpanda build --jsonexited 0 when the execution or build had actually failed, unlike their text paths.server: JSON-RPC rejections are not gateway failures
A JSON-RPC error object rides back on a healthy node connection — the node processed and rejected the request. Returning 502 (with the CLI's "temporarily unreachable — retry" hint) made deterministic failures look transient: transcripts show an agent retrying
debug_getBadBlocks(-32601) four hours after first learning the client doesn't support it, and revert reasons ("stack underflow", "invalid opcode") arriving triple-wrapped as gateway errors during EIP testing. JSON-RPC errors now return 400 with the error'sdatapayload appended (it often carries the answer, e.g. a revert reason), and the CLI adds a do-not-retry hint keyed on the message — so it also improves output against older servers still wrapping these in 502.embedding + search: outages are bounded and honest
On 2026-07-08 the embedding upstream (OpenRouter) hung and three consecutive
panda searchcalls each blocked for the full 2-minute batch timeout during a live devnet investigation. Root cause: a singleremoteEmbedTimeoutshared by 500-document index batches and single-query embeds, with server and proxy timeouts identical so the server always timed out first with a generic error.Test plan
go test -race ./pkg/... ./modules/...clean,make lint0 issuesmake docker-sandboxbuilds; PEP 701 smoke test + new sandbox functions import in the image-cexecutes, query-raw success and failure both parse through2>&1 | json.load