Repository navigation
tui3: a picture's step row names the image model, and opening it shows the prompt - #1026
Merged
Merged
Conversation
…s the prompt `generate_image` is the one hand whose model a person chooses per call, and until now the step row said neither which model drew nor what it was asked for. The row was the bare tool name — `generate_image` and a clock — because the tool is in no gloss table and its target was never read out of anything. The row now reads `generate_image circle.png · seedream-5`. The file is the substance and takes the ink; the image model is a qualifier behind the middle dot and recedes to dim, which is the parameter hierarchy toolview.go already states for a read's line range and a bash call's `cd` prefix. It rides the two roads the row already draws from and no third: the file comes from the call's own `path` argument, or — because the tool names the file itself when nobody did — out of the result, through the same [app.picturePath] rule the picture preview has always used; the model comes out of the tail of that same result line, which is where the tool writes the model the request actually carried. Nothing new goes on the wire, and the surface never guesses at a default it is not in a position to know: an unknown model draws nothing at all. Opening the step shows what went IN, as prose rather than as the JSON it arrived in. The prompt leads, quoted and wrapped and capped at twelve lines like every other expansion; under it one dim line per other input the call gave, and then the model line — `drawn with seedream-5`, or `asked for best · drawn with seedream-5` when the call asked in its own words and the catalog answered with a name. A running generation shows the same block above its clock, because a prompt is readable long before the picture is. The picture and its whole path still close the block, untouched. The word is [modelui.ModelWord], which is the spelling this surface already uses for a model everywhere else, so no fourth one was invented. The picture hands join toolFit's middle-cut family and phoneTarget's basename family, so a narrow row cuts the path and keeps the model and a phone row gives the qualifier up first — both by the rules those branches already applied, not by a new one. A session test pins the contract the two packages share: the model that rode the request is what stands after `, generated on ` at the end of the result's first line, for the default and for a picked word alike. Reword that sentence and it fails there, where the fix is cheap, rather than in a terminal where the row would simply go quiet. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv
…de the file Met on the real-model drive: seedream refused a 256x256 request, so the call had no file and no attribution to put on the row — and the model it tried was in the failure line the expansion shows. The page says so rather than leaving a person to wonder why the qualifier is missing. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv
santoshkumarradha
marked this pull request as ready for review
September 14, 2026 03:19
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.
What the row shows now
generate_imagewas the one hand whose step row said nothing about itself: notarget and no model, because the tool is in no gloss table and its file is
usually a name the tool chose rather than one the caller wrote. The row was
generate_imageand a clock.It now reads:
the parameter hierarchy
toolview.goalready states for aread's line rangeand a
bashcall'scdprefix;modelui.ModelWord), the one this surfacealready uses for a model everywhere else. No fourth spelling was invented.
Opening the step (click it, or ↑/↓ + enter) shows what went IN, as prose:
The prompt leads, quoted, wrapped, capped at twelve lines with the existing
… N more linesfoot. Under it one dim line per other input the call actuallygave — an input nobody gave has no line, because "default" is a word this
surface is not in a position to fill in. A running generation shows the same
block above its clock: a prompt is readable long before the picture is.
Where the name comes from
One road, no new field on the wire:
pathargument, else the path out of the result — throughapp.picturePath, the rule the picture preview already used… , generated on <model>— written byinternal/session'sdescribeGeneratedImagefrom the samemodelvariable the request carriedmodelargument, fromEvent.ArgsThe model is chosen inside the tool, after the call's word is resolved
against the live catalog, so the result is the only place the answer exists. The
surface does not re-derive it and does not show the session's default as a
stand-in — a hosted task room's row is drawn by this same composer from a node
whose default this window was never told.
internal/session/tools_image_test.gopins the contract between the twopackages: the model that rode the request is exactly what stands after
, generated onat the end of the result's first line, for the slot defaultand for a picked word alike.
One thing deliberately NOT built
The brief asked for
asked for X · drew with Y because <reason>. That casecannot happen. A model word
generate_imagecannot use is REFUSED before apenny is spent (
no image model matches "xyz",fish-audio/s1 makes speech, not image) — the tool never silently substitutes. Writing that branch would bedescribing machinery that does not exist. What does happen and is shown is
asked for best · drawn with seedream-5: the request and the answer, both real,both off roads already there.
Evidence
Laptop:
go build ./...,go vet ./...,gofmt -l internal/ cmd/clean.Spark gate —
~/af-imgmodel, detached onfeat/image-step-names-model:and after the manual follow-up commit:
ok internal/manual 1.660s,ok internal/e2e 0.343s(the untagged needle gate).Real-model drive —
bin/aforge chat --debugin tmux at 200×50 on Spark,moonshotai/kimi-k3, a real OpenRouter key, ~$0.25. Screens underspark:~/af-imgmodel-evidence/.The row, after a real generation (
success3/, verbatim):The same row while it ran — the file from the arguments, no model yet:
The opened step, on a call whose generation was refused by the image model
(the first drive, verbatim — wrapped at the frame, not truncated):
— the prompt quoted and wrapped, the one input the call gave, then the picture
block. No model line, because that call produced no picture to attribute; the
model it tried is in the failure the same block shows, and the manual now says
so in as many words.
Not verified by hand: the
drawn with <model>/asked for … · drawn with …line in a real terminal (covered by
internal/tui3/imagemodel_test.go; the drivethat produced a successful picture would not stay on the row long enough to open
it without re-sending the prompt, so the capture was abandoned rather than paid
for). A real
--host/ task-room row — the composer is shared, so it shouldfollow, but it was not driven. The phone tier.
Owed, not in this change: a FAILED generation could name its model as a
qualifier too — the fact is in the result, in a different sentence shape. Doing it
properly means one marker spelled the same way in every outcome of
describeGeneratedImageand its failure strings, which is a respell ofperson-facing text and belongs in its own change.
🤖 Generated with Claude Code
https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv