Repository navigation
feat(flows): select per-node models and session config options - #844
Conversation
Apply ordered run defaults and node configuration before the first ACP prompt, preserve creating-client use, and pin persistent handles across same-session replay. Record requested and accepted settings in v1 flow bundles. Validation: focused configuration tests, declared coverage, documentation checks, mutation testing, Python unit tests, and built Codex first-turn receipts passed. Aggregate check retains three unchanged conformance failures; wrapper-exited also fails on the untouched baseline. Independent coordinator review remains pending.
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
|
Codex review: blocked before merge. What this changesThis PR adds per-node model and ordered session-option selection to ACP flows, with run defaults and persistent-session replay. Example: A Codex flow node requests modelId gpt-6-luna and reasoning_effort medium.
Review scores
ProductKind: Feature · Worth it: Needs a maintainer decision · Fix scope: Complete Merge readiness⛔ Blocked before merge - 1 item remains Keep this PR open: it adds a capability missing from main and resolves the previous compatibility finding; the persistent-handle settings contract still needs a maintainer decision. Priority: P2 Decision needed
Before merge
FindingsNone. Tests
Agent review detailsHow this fits togetherThe flow runner translates node definitions and CLI defaults into ACP session controls, then records prompt results and configuration acknowledgements in run bundles. flowchart TD
A[Flow definition and CLI defaults] --> B[Flow runner]
B --> C[Session settings and binding]
C --> D[Shared session configuration]
D --> E[ACP adapter]
E --> F[Prompt result]
C --> G[Run bundle]
F --> G
Technical reviewBest possible solution: Adopt the scoped modelId surface and shared configuration path once the persistent-handle settings contract is decided. Do we have a high-confidence way to reproduce the issue? This is a feature request; main's node schema, session-binding path, and CLI registration confirm the missing selection surface. Is this the best way to solve the issue? The implementation appropriately extends the existing ordered configuration owner and preserves legacy metadata, with persistent-handle semantics awaiting an owner decision. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against 0d874f9a98de. Provenance checked
TestingProof path: shipped entry point. SecurityNone. EvidenceWhat I checked:
Likely related people:
Review metrics
LabelsLabel changes:
Label justifications:
Rating scale6/6 🦀 challenger crab · 5/6 🦞 diamond lobster · 4/6 🐚 platinum hermit · 3/6 🦐 gold shrimp · 2/6 🦪 silver shellfish · 1/6 🧂 unranked krab. Overall follows the weaker of proof and patch quality; ✨ marks media proof (a screenshot, video, or linked artifact) that directly shows the changed behavior. WorkflowClawSweeper edits this one comment on every review. Comment HistoryReview history (6 earlier review cycles)
Reviewed October 16, 2026, 3:06 PM ET / 19:06 UTC (Revision 7). |
|
Real-adapter proof on head Flow ( import { acp, defineFlow } from "acpx/flows";
const settings = { model: "gpt-6-luna", configOptions: [{ configId: "reasoning_effort", value: "medium" }] };
export default defineFlow({
name: "node-settings-proof",
startAt: "isolated",
nodes: {
isolated: acp({ ...settings, session: { isolated: true }, prompt: () => "Reply with exactly: ONE" }),
first: acp({ ...settings, session: { handle: "pinned" }, prompt: () => "Reply with exactly: TWO" }),
reconnect: acp({ session: { handle: "pinned" }, prompt: () => "Reply with exactly: THREE" }),
},
edges: [{ from: "isolated", to: "first" }, { from: "first", to: "reconnect" }],
});$ node dist/cli.js --cwd "$SCRATCH/workspace" --deny-all --format json --timeout 180 flow run proof.flow.mjs --default-agent codex
exit 0
"status":"completed", "outputs":{"isolated":"ONE","first":"TWO","reconnect":"THREE"}The adapter's defaults are Isolated node: first turn. Excerpt from {"id": 1, "method": "session/new", "params": {"_meta": {"claudeCode": {"options": {"model": "gpt-6-luna"}}}}}
{"id": 1, "result": {"configOptions": [{"id": "model", "currentValue": "gpt-6.1-sol"}, {"id": "reasoning_effort", "currentValue": "low"}]}}
{"id": 2, "method": "session/set_config_option", "params": {"sessionId": "01a0f398-3e9b-78d0-bb61-5a09207862a7", "configId": "model", "value": "gpt-6-luna"}}
{"id": 2, "result": {"configOptions": [{"id": "model", "currentValue": "gpt-6-luna"}, {"id": "reasoning_effort", "currentValue": "low"}]}}
{"id": 3, "method": "session/set_config_option", "params": {"sessionId": "01a0f398-3e9b-78d0-bb61-5a09207862a7", "configId": "reasoning_effort", "value": "medium"}}
{"id": 3, "result": {"configOptions": [{"id": "model", "currentValue": "gpt-6-luna"}, {"id": "reasoning_effort", "currentValue": "medium"}]}}
{"id": 4, "method": "session/prompt", "params": {"sessionId": "01a0f398-3e9b-78d0-bb61-5a09207862a7", "prompt": [{"type": "text", "text": "Reply with exactly: ONE"}]}}
{"id": 4, "result": {"stopReason": "end_turn", "model_usage": ["gpt-6-luna"]}}Persistent handle {"id": 4, "method": "session/prompt", "params": {"sessionId": "01a0f398-5544-7ab0-940b-32d48aaa916f", "prompt": [{"type": "text", "text": "Reply with exactly: TWO"}]}}
{"id": 4, "result": {"stopReason": "end_turn", "model_usage": ["gpt-6-luna"]}}
{"id": 1, "method": "session/resume", "params": {"sessionId": "01a0f398-5544-7ab0-940b-32d48aaa916f", "_meta": {"claudeCode": {"options": {"model": "gpt-6-luna"}}}}}
{"id": 1, "result": {"configOptions": [{"id": "model", "currentValue": "gpt-6.1-sol"}, {"id": "reasoning_effort", "currentValue": "low"}]}}
{"id": 2, "method": "session/set_config_option", "params": {"sessionId": "01a0f398-5544-7ab0-940b-32d48aaa916f", "configId": "model", "value": "gpt-6-luna"}}
{"id": 2, "result": {"configOptions": [{"id": "model", "currentValue": "gpt-6-luna"}, {"id": "reasoning_effort", "currentValue": "low"}]}}
{"id": 3, "method": "session/set_config_option", "params": {"sessionId": "01a0f398-5544-7ab0-940b-32d48aaa916f", "configId": "reasoning_effort", "value": "medium"}}
{"id": 3, "result": {"configOptions": [{"id": "model", "currentValue": "gpt-6-luna"}, {"id": "reasoning_effort", "currentValue": "medium"}]}}
{"id": 4, "method": "session/prompt", "params": {"sessionId": "01a0f398-5544-7ab0-940b-32d48aaa916f", "prompt": [{"type": "text", "text": "Reply with exactly: THREE"}]}}
{"id": 4, "result": {"stopReason": "end_turn", "model_usage": ["gpt-6-luna"]}}
{
"handle": "pinned",
"acpSessionId": "01a0f398-5544-7ab0-940b-32d48aaa916f",
"requestedSettings": { "model": "gpt-6-luna", "configOptions": [{ "configId": "reasoning_effort", "value": "medium" }] },
"acceptedSettings": {
"model": { "requested": "gpt-6-luna", "applied": true, "accepted": "gpt-6-luna" },
"configOptions": [{ "configId": "reasoning_effort", "value": "medium", "acceptedValue": "medium", "reported": true }]
}
}In the two excerpts, every prompt runs on On the persistent-handle contract and global @superbiche · contributor · drafted with Claude Opus 5.5. |
|
On the option-value finding: ACP session config options are @clawsweeper re-review @superbiche · contributor · drafted with Claude Opus 5.5, reviewed before posting; the voice and decisions are mine. |
|
🦞👀 Re-review progress:
|
Omit requestedSettings and acceptedSettings from the session bindings printed by flow run --format json; the run bundle keeps them. Pin global --model bundle evidence for shared persistent handles. Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
@clawsweeper re-review Please review current head @superbiche · contributor · drafted with GPT-6.1 Sol. |
|
🦞👀 Re-review progress:
|
vincentkoc
left a comment
There was a problem hiding this comment.
Technical review of head 034221c found no actionable P0–P2 defects in the supplied diff and source context. Ordered configuration, persistent-handle conflicts, and replay acceptance are checked before prompting. No contributor code was executed locally.
Not ready to land yet:
- The branch currently conflicts with main. A merge-tree comparison against 289c04f found the conflict in CHANGELOG.md only. Integrate current main while preserving all existing release history and Unreleased entries, then run the full code and docs CI on the resulting head. Older green checks are not evidence for that integration.
- The new modelId/configOptions surface and first-settings pinning contract for persistent handles still need the explicit maintainer decision requested in the PR body. This technical review does not approve that permanent contract.
vincentkoc
left a comment
There was a problem hiding this comment.
Approved the modelId/configOptions surface and first-settings pinning contract for persistent handles. Omitted later fields inherit the pinned settings; conflicting explicit selections fail; reconnect preserves the same ACP session or fails before prompting. Legacy model metadata remains inert.
The main integration changes no introduced feature source/test/doc patch across 23 non-changelog files, so the completed independent P0-P2 review remains applicable. The only manual repair preserves existing changelog entries and appends the flow entry. All 12 exact-head CI jobs passed: https://github.com/openclaw/acpx/actions/runs/41210298168.
Retained the two small help assertions: they cover the new optional description override and unchanged one-shot default. Production flow behavior is proven by the integration tests, not those helper assertions.
|
Landed as ba09c49. Approved per-node model/configuration selection and first-settings pinning for persistent handles. Integrated main with only a changelog conflict repair, preserving the reviewed feature patch and contributor ancestry. Reviewed head 72a84bc; full code and docs CI passed all 12 jobs: https://github.com/openclaw/acpx/actions/runs/41210298168. Thanks @superbiche! |
Related: #533, #843
What Problem This Solves
Flow authors cannot select a node's model and adapter options before its first turn. A flow run only accepts a run-wide
--model, and rejects--config-option.User Impact
ACP nodes can declare
modelIdand orderedconfigOptions, with defaults from--modeland repeatableflow run --config-option <key=value>. The node model overrides the run default; options run in order after model selection and before the prompt. Selection rejection or timeout prevents prompting.The existing passthrough
modelkey stays inert metadata, including numeric, string and object values. This preserves the compatibility boundary requested in #485 (comment).The persistent-handle contract pins the first settings. Later omitted fields inherit them; conflicting explicit selections fail. Another handle permits different settings. Reconnect loads the same ACP session and restores its selections or fails before prompting. The model/configuration surface and first-settings pinning contract are approved for landing.
Why This Change Was Made
This extends the one-shot configuration shape from #533 to flow nodes. Controls use the session's creating client, in order: model, run options, node options, prompt.
Bundles gain optional requested/accepted settings on session bindings and step snapshots. The printed JSON result omits those settings. Definition snapshots retain
modelId; legacymodelmetadata is not promoted into configuration. Existing flows without settings retain their previous bundle shape. A run-wide model adds settings evidence but does not create a node-level conflict.Configuration acknowledgements are not provider-usage attestation. Persistent creation controls are recorded in binding and step evidence, rather than
events.ndjson. The existing v1 bundle schemas remain additive. Reconnects that restore only options can still send redundant configuration controls; removing that redundancy remains outside this change.Evidence
The earlier real-adapter proof is retained at #844 (comment). It exercised the original control pipeline before this compatibility repair; it is not a fresh adapter run on the current candidate.
The repair adds persistent and isolated flow regressions for legacy metadata with no selection, run defaults and explicit
modelId, plus the v0.19.5 schema comparison. Existing tests cover ordering, rejection, pinning, same-session replay, evidence provenance and JSON output.On
034221c0, formatting, typecheck, lint, CLI/viewer builds, docs checks and normal commit hooks pass. The declared flows/runtime coverage target meets its 85% gates; the configured mutation target scores 91.98%.The full test run has 3,075 passes, 15 skips and one failure:
conformance retires wrapper-exited adapter and its transport. The same test fails on an untouched upstream archive atfacec6f; the merged upstream0d874f9differs from that baseline only in release workflow/docs, not the implicated code. This existing gate failure remains explicit and is not represented as a green full check.Independent Opus 5.5/medium artifact review reports no P0–P2 defects and passes with residuals. Current-candidate coverage is local/source/mock evidence; no fresh live-adapter run was performed. The first-prompt reconnect edge was source-reviewed through saved preference replay. Slophammer parity remains for CI because the checker is not installed locally.
@superbiche · contributor · drafted with GPT-6.1 Sol, reviewed before posting; the voice and decisions are mine.
Maintainer integration validation
Integrated main
62cd9826d15ea866b866b0e53015b2e9eea60900at head72a84bcce0df5be22bbdff86991df1be944c9ed6, including the landed runtime setup timeout, ACP message observer, and approved development-tool updates. The only manual conflict was CHANGELOG.md: preserve incoming entries and append the original flow entry to the existing Changes section. All 23 non-changelog introduced feature patches are identical to the previously reviewed and validated head009b112b9d997fb78c8fb9716b0b685ea2783384; contributor ancestry and inert legacymodelmetadata behavior are preserved.git diff --checkand the outgoing personal-data scan pass.Previous full code and docs CI passed: https://github.com/openclaw/acpx/actions/runs/41173135869. Fresh exact-head integration CI passed all 12 jobs, including Node 22/24/26, coverage, mutation, format, types, lint, builds, docs, conformance, and Slophammer: https://github.com/openclaw/acpx/actions/runs/41210298168. This checkout is code-only; no project dependency-backed tests were executed locally for this integration. The persistent-handle settings contract is approved for landing.