Repository navigation
feat(graph): read the final candidate from the last text producer - #365
Conversation
content(), protected and TargetOutcome.available now read the output of the last operation that produces text. When that operation did not succeed, the target has no final candidate and its outcome gives the reason; earlier text is no longer substituted. value() gains a producer= argument to read one operation's own output. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
[Medium impact] The change affects result-reading behavior in Graph SDK workflows. The PR appears safe to merge, with a non-blocking concern about reads from operations with repeated names. Findings
SummaryThe PR makes final-candidate reads use the last operation that produces text, rather than falling back to earlier output.
Reviews (1) · Last reviewed commit: "style(tests): format final-candidate spe..." · Reviewed by Greptile |
| operation named ``producer`` only; None if never produced.""" | ||
| outputs = self.state.rows[self._index(target)].outputs | ||
| if producer is not None: | ||
| return outputs.get(self.prepared.names.index(producer), {}).get(port) |
There was a problem hiding this comment.
Repeated names hide later outputs
value(..., producer=name) silently selects the first operation with that name. Workflow.flatten() allows repeated names, so running two operations called redact makes the second output impossible to select through this API. Reject ambiguous names or give callers a way to select each operation instead of silently returning the first output.
There was a problem hiding this comment.
Could we reject duplicate flattened operation names during preparation? With two operations named redact, value(target, producer="redact") returns the first output and offers no way to select the second. content() and protected still select the correct final output, so this seems non-blocking, but explicit inspection should be unambiguous.
There was a problem hiding this comment.
Yes—reject duplicate flattened operation names during prepare, before building the plan. That makes producer=name unambiguous without changing its API; nested workflows can still reuse local names when their flattened, prefixed names differ. A stable rejection reason such as duplicate_operation_name would also make the failure explicit.
|
The final-producer change and #354 address two different places where stale text can survive. Selecting the last text-producing operation still leaves the repair loop inside that operation responsible for returning its latest candidate. Can we keep a multi-repair case through the Rewrite route when these changes come together? That would cover the RFC’s requirement that the final assessment applies to the candidate actually returned. |
|
The November 4 GB300 rerun covers the two fixes separately now. At |
A target's final candidate is now the output of the workflow's last text-producing operation. Before, the result used the latest text from any operation, so when a later step failed, an earlier step's text could be returned as the final candidate. An earlier output can still be read on request, by name.
What changes
TargetOutcome.available,ProtectionResult.content()andProtectionResult.protectedread only the last text-producing operation's output. That is the same operation the covering verifiers are bound to. If it did not succeed, the target has no candidate and keeps its own reason.ProtectionResult.value(target, port, producer=name)returns that operation's output for the target. Withoutproducer,valuekeeps its meaning: the latest value of the port from any operation.TargetOutcome.withheld_byand the member outcomes already explain group and dependency withholding. New spec checks pin this.anonymizer.graph.__all__is unchanged (24).Checks
make checkpasses.pytestgives 1593 passed.final_textis rejected by the existing seal.Stacks on the checks-and-reasons PR.
🤖 Generated with Claude Code