Skip to content

Derive ReAct text completion from the task output - #272

Merged
deepfates merged 3 commits into
mainfrom
fix/270-task-text-output
Oct 2, 2026
Merged

deepfates merged 3 commits into
mainfrom
fix/270-task-text-output

Conversation

@deepfates

Copy link
Copy Markdown
Owner

A one-text-output ReAct task declared answer but asked the model to finish in next_thought. In Dwell's observed turns, that mismatch accompanied nonempty "no reply" summaries that the host correctly published. This change derives the step's text field and description from the task output, so the request and completion share one declaration.

The existing typed/constrained submit path stays intact. Native and textual tools, JSON fallback, last requests, saved agents and legacy demonstrations use the derived roles. Durable history still uses next_thought/tool_calls; boundary projection preserves existing conversations. A task named tool_calls uses agent_tool_calls for its written calls. Scripted model responses/custom step renderers must use the task output name.

Validation: mix check passed (59 doctests, 9 properties, 3588 tests, 0 failures; 13 skipped, 221 excluded). A final focused run including the additional textual-call collision test passed all 72 tests. Coverage includes captured requests/adapters, history and demo collisions, blank and nonempty completion, and existing terminal/last-request behavior. The new regression suite fails against unchanged main (20 failures in the original 25-test set) and passes with the implementation. No models, production services or social publishing were invoked. This repairs the contract; it does not prove improved model behavior. Nonempty silence prose still remains output, and malformed-wrapper detection is outside this change.

Closes #270. Context: https://github.com/GroveResearch/dwell/issues/184#issuecomment-5942331037

@deepfates deepfates left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independent review of cded163. The central change is coherent: task-field descriptions drive the live step, loop history retains its durable vocabulary, and no prose classifier turns nonempty output into silence. I ran the affected completion/step-contract/round-trip/native-reduction/JSON-fallback tests: 59 tests, 0 failures. No provider calls.

One medium contract gap remains before I would call generic output-name history support complete: a host-supplied answer-only turn for a task whose output is tool_calls silently disappears on replay. step_turn/2 (lib/imp/predict/react_v2.ex:1493–1500) treats any tool_calls key as durable call storage; Chat then treats the string as a native-call turn (lib/imp/adapter/chat.ex:1200), leaving no assistant message. A static-model probe with Imp.react("intent -> tool_calls", [], lm: lm) and Imp.History.new([%{intent: "before", tool_calls: "PRIOR AUTHORED WORDS"}]) captured no assistant history; the otherwise identical answer task retained the words. The new generic-name tests only replay the loop's own normalized history, so do not catch this boundary. The guard predates this patch; this is an uncovered limitation of the broader compatibility claim, not evidence that ordinary answer tasks regressed.

Please either handle the unambiguous binary task answer before classifying the reserved storage key, with a host-history regression across native/written adapters, or explicitly bound the supported host-history contract. Keep existing real durable call lists unchanged. No repository edits made during review.

@deepfates

Copy link
Copy Markdown
Owner Author

Addressed the independent review's supplied-history collision in c23f2d8. When the task text output is named tool_calls, an incoming historical string is now projected as authored text; an actual call collection retains the existing interpretation. The durable history is unchanged.

The captured-prompt regression covers native/textual modes and atom/string historical keys. It fails before the repair (27 tests, 1 failure) and passes after; the broader completion/history/adapter/restore/last-action selection passes all 99 tests. No models or production calls.

@deepfates deepfates left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up independent review of c23f2d8: the supplied-history collision is resolved. I reran the original disposable static-model probe: the tool_calls text task now preserves PRIOR AUTHORED WORDS as the assistant message, matching the ordinary answer case. The binary guard leaves actual call collections on the existing durable-history path, and FieldMap.put avoids parallel atom/string aliases.

Rechecked the repair diff and ran task-completion, written-chat-history and round-trip restoration tests: 30 tests, 0 failures. The new regression covers native/written modes, atom/string historical keys, and unchanged retained history. No remaining blockers found in this reviewed head. This establishes the declaration/replay contract, not improved live model behavior. No repository changes or provider calls during review.

@deepfates

Copy link
Copy Markdown
Owner Author

CI repair in 98cafc4 changes only the existing narrow Chat Dialyzer filter from {820, 8} to {829, 8}. The unchanged defensive fetch_meta/3 fallback moved by nine lines. A raw module diagnostic confirms :pattern_match_cov at {829, 8} for pattern <_map@1, _key@1, _default@1>; no warning class or file-wide filter was added.

Before: Total errors: 142, Skipped: 141, Unnecessary Skips: 1 (the stale line-820 filter). After: full local mix dialyzer.check passes with Total errors: 142, Skipped: 142, Unnecessary Skips: 0. The completed CI lanes on c23f2d8 all passed except this diagnostic; package.check was still running when checked.

@deepfates
deepfates marked this pull request as ready for review October 2, 2026 02:33
@deepfates
deepfates merged commit ba86336 into main Oct 2, 2026
10 checks passed
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.

Use the task text output as the ReActV2 completion contract

1 participant