Release v0.3.0: resolved main_stuff on both execution modes#6
Merged
Conversation
RunResults.main_stuff is now required and non-null for a completed run. On the hosted path it is the main_stuff.json S3 artifact; on the blocking path the SDK resolves working_memory.root[main_stuff_name].content from the execute response, so both paths deliver the same content shape and consumers read results.main_stuff directly (no more main_stuff-or-pipe_output fallback / shape guessing). pipe_output stays as the supplementary full working memory (blocking path only). A completed run that cannot deliver a main stuff now raises the new MissingMainStuffError: a hosted 200 whose main_stuff is null, or a blocking response whose main_stuff_name names no working-memory root stuff. A falsy but present main stuff (empty list, 0) is a valid output and does not raise. Breaking: main_stuff was optional (Any = None). Bump 0.2.0 -> 0.3.0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PibWhJ6mPWdrkMqZATZpkJ
… result execute() now returns a PipelexExecuteResult (a DictRunResultExecute subtype) that exposes a resolved .main_stuff accessor, so blocking and durable results read their output the same way (result.main_stuff) with no working-memory spelunking. The internal blocking->RunResults mapper reads the same accessor, single-sourcing the resolution. Lives in its own module (execute_result.py) to avoid an errors<->runs import cycle. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PibWhJ6mPWdrkMqZATZpkJ
…del_extra dig PipelexExecuteResult is the Pipelex-branded layer, so main_stuff_name belongs as a declared field there rather than riding the neutral base's extension bag. Removes the model_extra lookup + isinstance re-narrowing; the .main_stuff property now reads self.main_stuff_name directly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PibWhJ6mPWdrkMqZATZpkJ
Greptile SummaryThis PR unifies completed-run output access around
Confidence Score: 4/5Mostly safe, with one contained API error-handling issue to fix. The main output-resolution paths are covered, but a hosted completed result that omits
What T-Rex did
Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Caller
participant Client as PipelexAPIClient
participant Hosted as Hosted /v1/runs
participant Runner as Bare /v1/execute
Caller->>Client: start_and_wait(...)
Client->>Client: supports_run_lifecycle()
alt hosted lifecycle
Client->>Hosted: POST /v1/start
Hosted-->>Client: pipeline_run_id
Client->>Hosted: "GET /v1/runs/{id}/results"
Hosted-->>Client: RunResults(main_stuff)
Client-->>Caller: result.main_stuff
else bare runner fallback
Client->>Runner: POST /v1/execute
Runner-->>Client: pipe_output + main_stuff_name
Client->>Client: PipelexExecuteResult.main_stuff resolves root[name].content
Client-->>Caller: RunResults(main_stuff, pipe_output)
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Caller
participant Client as PipelexAPIClient
participant Hosted as Hosted /v1/runs
participant Runner as Bare /v1/execute
Caller->>Client: start_and_wait(...)
Client->>Client: supports_run_lifecycle()
alt hosted lifecycle
Client->>Hosted: POST /v1/start
Hosted-->>Client: pipeline_run_id
Client->>Hosted: "GET /v1/runs/{id}/results"
Hosted-->>Client: RunResults(main_stuff)
Client-->>Caller: result.main_stuff
else bare runner fallback
Client->>Runner: POST /v1/execute
Runner-->>Client: pipe_output + main_stuff_name
Client->>Client: PipelexExecuteResult.main_stuff resolves root[name].content
Client-->>Caller: RunResults(main_stuff, pipe_output)
end
Prompt To Fix All With AIFix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
pipelex_sdk/client.py:535-536
**Preserve typed error**
`RunResults.model_validate(response.json())` runs before the absence check, so a completed `200` response that omits `main_stuff` raises a raw Pydantic validation error instead of `MissingMainStuffError`. That breaks the new typed-error contract for the same un-deliverable-output condition as `main_stuff: null`; check the decoded payload for a missing or null key before validating into the now-required `RunResults` model.
Reviews (1): Last reviewed commit: "refactor(execute): declare main_stuff_na..." | Re-trigger Greptile |
…n_stuff `RunResults.model_validate` ran before the main_stuff absence check, so a completed 200 that omits the key raised a raw Pydantic ValidationError instead of the typed MissingMainStuffError — while `main_stuff: null` was correctly caught. Inspect the decoded payload first so both the missing-key and explicit-null cases surface the same typed error for the same un-deliverable-output condition; a falsy-but-present main stuff still passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XTtTK4ViwgKLDbZQRHJfen
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
result.main_stuff.RunResults.main_stuffis now required and non-null for a completed run (wasAny = None).execute()now returns aPipelexExecuteResult— aDictRunResultExecutesubtype exposing a resolved.main_stuffaccessor, so a blocking result reads its output the same way a durableRunResultsdoes. Nomain_stuff or pipe_outputfallback, no working-memory spelunking, in application code.MissingMainStuffError(new, extendsPipelineRequestError, carriesrun_id): raised when a completed run cannot deliver a main stuff (hosted200with nullmain_stuff, or a blocking response whosemain_stuff_namenames nothing in the returned working memory). A falsy-but-present main stuff (empty list,0) is valid output and does not raise.main_stuff_nameis declared as a typed field onPipelexExecuteResult(not read out ofmodel_extra) — the Pipelex-branded subtype owns the concept; the neutralmthdswire model correctly leaves it in the extension bag.This is the SDK half of a coordinated breaking change also landing in
pipelex-sdk-js,pipelex-starter-python, andpipelex-starter-js(this repo's downstream starter ispipelex-starter-pythonrelease/v0.11.0, currently git-pinned to this branch).Why
Triggered by verifying the client-repo impact of
pipelexv0.37.0 /pipelex-apiv0.7.0 (PipeParallel always-combines + the main-stuff invariant). The breaking change itself forces no client changes — investigation in the workspace-rootTODOS.mdcovers all six client repos. This PR is the approved follow-on enhancement: since a completed run is now guaranteed to deliver a main stuff, the SDK resolves it for the caller instead of exposing the locator (main_stuff_name) and making the caller do the lookup.Test plan
make agent-check&&make agent-testgreenmain_stuff, blocking-raises-when-unlocatable, hosted-null-raisesCHANGELOG.md,README.md,docs/architecture.mdupdated🤖 Generated with Claude Code
https://claude.ai/code/session_01PibWhJ6mPWdrkMqZATZpkJ