Skip to content

feat(embed): let an embedder set the turn's close copy - #704

Merged
senamakel merged 8 commits into
epic/537-turn-qualityfrom
epic-537-702-oh
Oct 30, 2026
Merged

senamakel merged 8 commits into
epic/537-turn-qualityfrom
epic-537-702-oh

Conversation

@senamakel

@senamakel senamakel commented Oct 30, 2026 •

Copy link
Copy Markdown
Owner

What

Lets an embedder set the wording a turn is closed with when it stops at its tool-call cap or ends without a reply (CloseCopy: the model's cap instruction, the final-write instruction, the deterministic fallbacks and the repair prompts).

  • RuntimeBuilder::close_copy(CloseCopy) sets it per runtime; Turn::close_copy(CloseCopy) overrides it for one turn. CloseCopy and ENGLISH_CLOSE_COPY are re-exported from openhuman-embed.
  • It is carried on HostTurnEnv / OpenHumanRunContext (inherited by children) and read in one place, OpenHumanRunContext::close_copy(), which both context_wiring (FinalCallWrapUpMiddleware) and grounded_close / execute now take instead of the hard-wired OPENHUMAN_CLOSE_COPY. The two paths cannot drift apart.
  • product_copy::close_needles adds the instructions actually in force to the needle list, so the echo-strip still removes a reworded instruction the model repeats; is_final_summary recognises the copy's own "finished without a result" opening instead of a hard-coded English sentence.

The default stays ENGLISH_CLOSE_COPY, so OpenHuman's own behaviour is unchanged.

Cause: the close copy was a process-wide constant, so a host whose turns are chat replies to end users could not stop a capped turn from being told to write an operator report.

Closes #702
Part of tinyhumansai/chottu-core#537

Tests

  • an_embedder_close_copy_reaches_the_capped_turn (runtime copy and per-turn override reach the model and the checkpoint reply), the_default_close_copy_is_unchanged (openhuman-embed/tests/close_copy*.rs)
  • a_reworded_close_instruction_echoed_by_the_model_is_recognised and related product_copy tests (core)

Gates and caveats

fork/epic/537-turn-quality does not compile openhuman-core on its own (21 errors, from the merged tinyhumansai#8487 state: e.g. secure_open path, await in non-async fn), so the gates were run on a throwaway local branch = this branch + fork/pr-8487-followup (not pushed):

  • cargo test -p openhuman-embed --features inference,mcp,skills --test close_copy --test close_copy_default: pass, but only with the prompt screen bypassed locally. The security module artifact is not installed in this sandbox, so the screen holds every prompt; sibling embed turn tests (agent_lifecycle, observed_turns) fail identically here with the screen intact. Needs a CI run with the module fixture.
  • cargo test -p openhuman --lib -- agent::session_host::product_copy agent::session_host::driver::grounded_close agent::tinyagents::context: 50 pass, 2 fail (the_final_summary_of_a_halted_turn_gives_a_reason_and_names_the_tools, classified_halt_returns_partial_work_without_provider_usage); both assert on tool error text that arrives as [REDACTED] from the followup state and go through code this PR does not touch.
  • cargo clippy -p openhuman -p openhuman-embed --all-targets -- -D warnings: no diagnostics in files changed here (existing unused-import errors elsewhere).
  • cargo fmt -- --check: clean.

Review round 1 follow-up

  • Added wrap-up coverage (wrap_up_close_copy, max_iterations >= 3): the penultimate request carries the custom final_write_instruction, the last permitted one the custom max_iteration_instruction, no English default.
  • close_needles now includes stop_note_preamble; grounded_close test pins the echo repair with a reworded copy.
  • The host policy resolves the default once via OpenHumanRunContext::close_copy().
  • builder-setters / api-index docs regenerated.
  • The per-turn override lives on Turn rather than TurnRequest on purpose: TurnRequest is the serialized inference.agent_chat wire contract and cannot carry copy.
  • Verification: the embed tests run only on a throwaway branch (this branch + fork/pr-8487-followup + a local prompt-screen bypass), because openhuman-core does not compile on the epic tip; two core tests (the_final_summary_of_a_halted_turn..., classified_halt_returns_partial_work...) fail identically on the base. The branch carries no bypass and net-zero submodule/Cargo.lock change.

senamakel and others added 8 commits October 30, 2026 19:25
Close and final-summary copy now comes from a CloseCopy carried on the run context instead of a fixed constant, so embedders can supply their own wording. Added product_copy helpers and embed builder defaults, plus tests covering custom and default close copy.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Refresh Cargo.lock to pick up the reworked tinytools, tinywallet, and tinybox dependency graph, and extend the close-copy tests to cover the updated embed behaviour.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…s to it

The host policy now carries the resolved CloseCopy, read through
OpenHumanRunContext::close_copy(), so the middleware and grounded-close
paths cannot drift on the default. A new embed test drives a four-call
capped turn and asserts the penultimate request carries the copy's
final_write_instruction and the last one its max_iteration_instruction,
for the runtime copy and the per-turn override.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
…e echo repair

Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Reformatted the assertions and turn construction in the wrap-up close copy test to satisfy rustfmt line-length limits. No test behaviour or coverage changed.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@senamakel
senamakel merged commit a4c226c into epic/537-turn-quality Oct 30, 2026
0 of 4 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.

1 participant