Skip to content

Fix/docker version badge - #11

Merged
jay-m-dev merged 8 commits into
mainfrom
fix/docker-version-badge
Sep 22, 2026
Merged

jay-m-dev merged 8 commits into
mainfrom
fix/docker-version-badge

Conversation

@jay-m-dev

Copy link
Copy Markdown
Collaborator

This pull request introduces improvements to how Reason+Act agent iteration limits are handled and communicated in both the backend Docker build process and the frontend UI. The main goals are to ensure the reported app version is accurate, prevent accidental "dirty" builds, and provide better feedback and suggestions to users when an agent run is truncated due to hitting its iteration cap. The UI now offers actionable hints and clearer messaging around iteration limits, and the Docker build process avoids freezing version information.

Docker build process improvements:

  • .dockerignore: Added src/asaree/_version.py to prevent copying a stale, build-generated version file into the image, which could otherwise freeze the reported app version.
  • Dockerfile: Updated build steps to mark all missing files as "assume-unchanged" in the mounted git index, preventing "dirty" version tags due to partial checkouts and ensuring accurate version reporting in both application and test images. [1] [2]

Frontend: Reason+Act node iteration cap feedback:

Frontend: Iteration cap suggestions and wiring analysis:

  • frontend/src/components/protocol/ProtocolCanvas.tsx:
    • Computes the recommended minimum iteration cap for each Reason+Act node based on wiring analysis and recent run data.
    • Passes these recommendations and truncation evidence to node inspectors and other panels.
    • Ensures all node references in transcripts and test results use display names, not raw IDs. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]

Frontend: Inspector actionable hints:

  • frontend/src/components/protocol/ReasonActPatternNodeInspector.tsx:
    • Displays a warning and a one-click "Use N" button when the configured iteration cap is too low, based on wiring or recent truncation.
    • Explains why the suggested value is needed and what happens if the cap is too low. [1] [2] [3] [4] [5]

Jay Moran added 8 commits September 21, 2026 16:02
Two things made the GUI's version badge lie. `src/asaree/_version.py` is
gitignored but was not in .dockerignore, so a host-side `uv sync` left one
behind that `COPY src/` baked into the image -- and since _app_version()
prefers it over the distribution metadata, the badge froze at whatever commit
that checkout last built.

Separately, /app is a partial checkout (no frontend/, tests/, docs/, or root
files), so everything missing reads as deleted against the mounted index and
`git describe --dirty` returns -dirty. setuptools_scm treats dirty like
distance, so building the v0.6.0 tag produced 0.6.1.dev0: every release
announced itself as a prerelease of the next one. Marking the absent paths
assume-unchanged before `uv sync` restores the clean describe the tag names.

Verified: a build of the v0.6.0 commit now installs asaree==0.6.0 and
_app_version() returns 0.6.0, so the badge reads v0.6.0.
A Reason+Act run that hits max_iterations does not fail: Motoro's loop
falls through its for...else, keeps the last tool result as the output,
and still marks the run completed. Downstream that is indistinguishable
from a finished run -- the Output Parser reads a tool dump instead of a
report, and every contracted field the dump does not happen to state
comes back null. That is what the "Extracted fields: null" reports were.

The cap is a safety stop, not a budget: the agent exits the moment it
answers, so a cap above what a run needs costs nothing while one below
it silently truncates. Raise the new-node default from 15 to 30 and, in
the inspector, offer the number the driven agent's wiring implies --
measured from the run that failed, where one tool call costs one
iteration and a Script costs several (run it, then write throwaway
Python to read the JSON it left on disk).
Motoro reports a Reason+Act run that exhausts max_iterations as
`completed`, keeping whatever the last Act returned as its output. Two
things downstream then lie: the node run shows a green "Done", and a
wired Output Parser handed a tool dump instead of a written answer
produces a payload whose every field is null -- rendered as a tidy list
of results whose answer happens to be "null".

Read the truncation off agent_runs.pattern_overrides, which the ReasonAct
pattern already persists (reason_act_state.max_iterations_hit); the step
rows cannot answer it, since the stored Act step carries the pre-hook
should_continue and is false on every run. Carry it as a `truncation`
flag on the completed node run rather than a new status: ~20 sites read
that vocabulary to mean "did this node produce usable output", and for a
truncated run the answer is still yes. The badge goes amber, and the
output panel says what happened and which number to raise.

Separately, flag an all-null payload with a caveat. The extractor types
every contracted field `T | None` and may not infer, so "found nothing"
and "the answer genuinely had none of these" are the same object; one
null among real values is a real partial reading and stays silent.
The wiring-derived `max_iterations` suggestion only existed inside the
Reason + Act inspector, where you had to already be looking at the field to
see it. It now drives the node's own warning triangle and the pre-run
"run anyway?" scan, so an undersized cap is visible on the canvas and
interrupts a Run before it burns tokens on a loop that will be cut off.

The suggestion moves to a single `suggestedIterationsByPattern` memo on the
canvas so the node card and the inspector can't disagree about the number.

A replicate whose agent hit the ceiling no longer counts as scored: the
metrics it produced are real measurements of an unfinished run, and letting
them project would make a cell read "3/3 scored" when all three agents
stopped mid-work. "Scored" is `metric_values` being set, so withholding the
projection excludes it from the cell accents, the design-history counts and
the factorial analysis at once. The numbers survive on the attempt and in
`artifacts["measurement"]`, and `artifacts["truncation"]` is what lets a
"completed but unscored" replicate explain itself in the Runs tab.
Node progress listed one row per node in the graph keyed by node id, and only
the agents had a name to fall back on -- so a dataset, an output parser or a
script showed a bare uuid that matches nothing the user can point at on the
canvas.

lib/nodeNames.ts is the shared answer: a node's own label when the user set
one, otherwise the placeholder its card already shows for that type, with
same-named nodes numbered in canvas order so three unlabelled Scripts don't
read as three identical rows.
The agent node already badges "Hit iteration limit" after a truncated run,
but the number that caused it is configured on the Reason + Act node driving
that agent, which showed nothing -- so the finding pointed at a node with no
fix on it. The truncation now crosses that edge and raises the pattern node's
own warning triangle.

Deliberately not a findNodeConfigIssues entry: that scan is static pre-flight
state, and a past run's outcome would keep blocking the pre-run dialog after
the cap was already raised, until the next run happened to replace it. The
card warning clears as soon as the cap is above what died.

An observed truncation also outranks the wiring heuristic when suggesting a
number -- a run that died at 40 is the loop itself saying 40 was short, where
suggestedMaxIterations is only guessing from what's connected.
A Test Run reports itself only through its own results panel -- it never
seeds runQuery, since list_protocol_runs excludes test runs -- so the pattern
node's new warning could only ever come from a production run. That is
backwards for the one finding it carries: a Test Run is how you iterate on
the canvas, so a cap that truncated one has to reach the node you would fix.

The node badges keep reading runQuery alone (that is the run the canvas is
watching); only the truncation finding takes whichever run is newer, so
raising the cap and running for real clears what a Test Run left behind.
Every Run button routes through RunConfirmDialog, which is the last point
where raising the cap is cheaper than paying for the run -- and the most
expensive case, "Run all cells", is exactly the one that repeats a truncation
across every replicate.

The canvas can name the node: findNodeConfigIssues takes the caps its agents
actually died at and reports them in place of the wiring estimate, evidence
instead of a guess. A run outcome is admissible in that static scan only
because it is gated on the cap still being at or below what failed -- raise
it and the finding is gone, without waiting for another run to prove it.

The Runs tab's dialogs have the stored graph and a trial list but no run, so
they can't tell which node's cap did it; they report the same thing per
replicate instead, in the same amber the node badge and the Runs tab badges
already use.
@jay-m-dev
jay-m-dev force-pushed the fix/docker-version-badge branch from 1e1a860 to 549c991 Compare September 22, 2026 20:25
@jay-m-dev
jay-m-dev merged commit 88534a7 into main Sep 22, 2026
2 checks passed
@jay-m-dev
jay-m-dev deleted the fix/docker-version-badge branch September 22, 2026 20:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant