Skip to content

fix(flows): exempt workflow proposal tools from tokenjuice compaction (canvas renders ≥4-node graphs)#4888

Merged
graycyrus merged 4 commits into
tinyhumansai:mainfrom
graycyrus:fix/flows-proposal-tabulation-main
Jul 15, 2026
Merged

fix(flows): exempt workflow proposal tools from tokenjuice compaction (canvas renders ≥4-node graphs)#4888
graycyrus merged 4 commits into
tinyhumansai:mainfrom
graycyrus:fix/flows-proposal-tabulation-main

Conversation

@graycyrus

@graycyrus graycyrus commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

The workflow_builder copilot's proposal never reached the canvas for non-trivial graphs. Root cause: extract_workflow_proposal (ops.rs) reads the post-compaction agent history, but ToolOutputMiddleware::after_tool runs tinyjuice on every tool result first — and the JSON compressor tabulates any uniform node-array ≥3 rows / ~512 bytes into [json table: graph.nodes …], stripping the type:"workflow_proposal" marker. So serde_json fails, extraction returns None, has_proposal=false, blank canvas. Small graphs slipped under the threshold and rendered; ≥4-node graphs vanished (nondeterministically — one build recovered via tinyjuice_retrieve + re-propose, another silently died).

Solution

Exempt the proposal-/persistence-emitting tools (propose_workflow, revise_workflow, edit_workflow, save_workflow, create_workflow) from both compaction passes (payload summarizer + tokenjuice) in ToolOutputMiddleware::after_tool. Their output is a machine-readable contract that downstream extraction + the frontend canvas parse structurally; compacting it serves no purpose. The per-tool char cap and shared byte-budget backstop are untouched.

Testing

  • 3 new extract_workflow_proposal tests (6-node graph survives, latest-of-many, ignores non-proposals).
  • 5 new middleware tests — including a baseline test proving tokenjuice really tabulates + strips the marker for a non-exempt tool, then that every exempt tool stays byte-for-byte intact.
  • openhuman::flows:: → 363 pass; openhuman::tinyagents::middleware:: → 39 pass.
  • GGML_NATIVE=OFF cargo check clean; cargo fmt --check clean.

Acceptance criteria

  • Repro gone — ≥4-node proposals extract intact → canvas renders deterministically
  • Regression safety — baseline (tabulation happens) + fix (exempt tools intact) tests
  • Diff coverage ≥ 80% on changed lines

Summary by CodeRabbit

  • Bug Fixes

    • Preserved workflow proposal results so large or detailed proposals remain complete and can be processed correctly.
    • Ensured the latest workflow proposal is selected when multiple proposals are present.
    • Improved handling of tool outputs while maintaining safeguards for oversized content.
    • Confirmed sampling results retain their content during compaction while remaining subject to size limits.
  • Tests

    • Added coverage for proposal extraction, output preservation, truncation, and non-proposal tool results.

… so the canvas renders ≥4-node graphs

extract_workflow_proposal (flows/ops.rs) scans agent history for a tool
result JSON containing "type": "workflow_proposal". But
ToolOutputMiddleware::after_tool ran the payload summarizer and tinyjuice
compaction on every tool result first — tinyjuice tabulates any uniform
object-array of >=3 rows over ~512 bytes into a `[json table: ...]` marker,
stripping the "type" field. Small graphs (under threshold) survived; graphs
with >=4 nodes got tabulated and the extractor found nothing, so the canvas
rendered blank.

Add COMPACTION_EXEMPT_TOOLS (propose_workflow, revise_workflow,
edit_workflow, save_workflow, create_workflow) and skip both the
payload-summarizer and tokenjuice stages for these tools' results, so their
self-describing JSON reaches agent.history() byte-for-byte. The per-tool
char cap and shared byte-cap backstop are untouched.

Tests: extract_workflow_proposal_survives_large_graph (+2 sibling cases) in
flows/ops_tests.rs; tool_output_leaves_propose_workflow_byte_for_byte_intact
(+ baseline tabulation proof, exempt-tool-name coverage, and a
COMPACTION_EXEMPT_TOOLS membership check) in tinyagents/middleware.rs.
@graycyrus
graycyrus requested a review from a team July 15, 2026 10:32
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 350b218f-eb66-4b63-a8f2-7b645730c070

📥 Commits

Reviewing files that changed from the base of the PR and between fe2a304 and e813fc4.

📒 Files selected for processing (2)
  • src/openhuman/flows/ops_tests.rs
  • src/openhuman/tinyagents/middleware.rs

📝 Walkthrough

Walkthrough

ToolOutputMiddleware now exempts workflow proposals from compaction and truncation, exempts sampling tools from compaction only, and adds tests for payload preservation and workflow proposal extraction.

Changes

Workflow payload preservation

Layer / File(s) Summary
Middleware exemption rules
src/openhuman/tinyagents/middleware.rs
Tool-specific predicates conditionally skip summarization, TokenJuice compaction, character caps, and shared byte-budget truncation.
Middleware exemption tests
src/openhuman/tinyagents/middleware.rs
Tests cover intact proposal payloads, normal non-exempt processing, oversized payload truncation, and sampling-tool behavior.
Workflow proposal extraction tests
src/openhuman/flows/ops_tests.rs
Tests cover large proposals, latest-result selection, and histories without workflow proposals.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ToolResult
  participant ToolOutputMiddleware
  participant Compaction
  participant Truncation
  ToolResult->>ToolOutputMiddleware: provide tool name and payload
  ToolOutputMiddleware->>ToolOutputMiddleware: classify exemptions
  ToolOutputMiddleware->>Compaction: process non-exempt payloads
  ToolOutputMiddleware->>Truncation: truncate non-exempt payloads
Loading

Possibly related PRs

Suggested labels: rust-core, bug

Suggested reviewers: senamakel

Poem

I’m a rabbit guarding graphs in JSON,
No token shears shall make them gone.
Proposals stay whole, samples stay clear,
The latest workflow hops near.
Tests thump softly: thump, thump, hooray!


Comment @coderabbitai help to get the list of available commands.

…mpt sampling tools from compaction

PR tinyhumansai#4888 exempted workflow proposal tools from tokenjuice compaction
(steps 1-2 of ToolOutputMiddleware::after_tool) but left the per-tool
char cap and shared ~16KiB byte-budget backstop (steps 3-4) in place.
A >=10-node proposal routinely exceeds that budget, gets truncated at
a UTF-8 boundary, and fails the whole-string JSON parse both
flows::ops::extract_workflow_proposal and the frontend's
parseWorkflowProposal do -- a second, size-triggered cause of the
blank-canvas bug, distinct from the tabulation one tinyhumansai#4888 fixed.

Also exempt get_tool_output_sample/get_tool_contract from compaction
(steps 1-2) only: tokenjuice's array-elision tabulation hides the real
response shape these tools exist to reveal, causing the model to
derive a wrong/nonexistent split_out.path. They stay subject to the
byte-cap backstop since their payload is intermediate context, not the
turn's final output, and can be genuinely large.

Split into is_compaction_exempt (proposal + sampling tools) and
is_truncation_exempt (proposal tools only) so each tool family's
exemption scope is explicit and independently testable.
…tabulation-main

# Conflicts:
#	src/openhuman/flows/ops_tests.rs
@graycyrus
graycyrus merged commit 390c1ca into tinyhumansai:main Jul 15, 2026
@coderabbitai coderabbitai Bot added bug rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. labels Jul 15, 2026
senamakel pushed a commit to M3gA-Mind/openhuman that referenced this pull request Jul 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant