Skip to content

Unified late-bound tool contract gate with compaction-safe transcript presence #5038

Description

@yh928

Summary

Extend contract-gating to every late-bound tool surface with a single, compaction-safe gate. #4995 gates per-action Composio tools; this adds the surfaces it does not cover — the generic composio_execute dispatcher, the MCP-registry bridge (mcp_registry_tool_call), and workflows (run_workflow) — and makes per-action gating resilient to context compaction.

Problem

Agents compose late-bound tool calls before the tool's full contract (input JSON schema + description) is in context, so they guess argument formats and slugs — e.g. a Composio Gmail search sent without the quotes the query syntax needs, or an invented GMAIL_LIST_MESSAGES in place of the real GMAIL_FETCH_EMAILS. #4995 (for #4853) fixed this for per-action Composio tools, but:

  • The generic composio_execute dispatcher, the MCP-registry bridge, and workflows have the same thin-schema problem and are not gated.
  • fix(composio): gate per-action tools on their full contract (#4853) #4995's per-action gate tracks "already surfaced" as an in-memory seen set per tool instance, which — as its own docs note — does not reset when the surfaced schema drops out of context via summarization / microcompact / trim. The model then acts on a schema it can no longer see.

Solution

A single ContractGateMiddleware in the agent harness (assemble_turn_harness) gating all four surfaces:

  • Presence is derived from the transcript, not per-tool-instance state: a [contract-gate:<digest>:<key>] marker leads a delivered contract message; before each model call the gate rescans tool-role messages and rebuilds the in-context set. A contract folded away by the summarizer / blanked by microcompact / dropped by trim is no longer present, so it is re-delivered (fail-safe) — closing fix(composio): gate per-action tools on their full contract (#4853) #4995's compaction gap.
  • The marker embeds an XXH3-64 digest of the exact contract bytes, so a summarized/rewritten contract fails the digest match and is re-delivered.
  • Full-schema discovery tools (describe_workflow, mcp_registry_list_tools, composio_list_tools) pre-credit the contracts they fully render, so there is no redundant re-delivery.
  • Per-action Composio is unified onto this gate; fix(composio): gate per-action tools on their full contract (#4853) #4995's tool-layer composio::contract_gate hookup is removed to avoid double-gating (the module is left in place, tracked for removal).

Scope: core (Rust). Kill switch OPENHUMAN_CONTRACT_GATE=0.

Acceptance criteria

  • composio_execute / MCP / workflows gated — the first call each turn to each surface, with its contract not in the transcript, is short-circuited with the full contract; the retry runs.
  • Compaction-safe presence — a contract dropped from context (summarize / microcompact / trim) is re-delivered; presence is transcript-derived and per-run.
  • Contract integrity — a rewritten/summarized contract body fails the payload digest and is re-delivered.
  • No double-gating with fix(composio): gate per-action tools on their full contract (#4853) #4995 — per-action Composio is gated exactly once (by the middleware).
  • Feature-gate safe — compiles and tests with flows / skills / mcp off (the gate degrades to pass-through).
  • Diff coverage >= 80% — the implementing PR meets the changed-lines coverage gate (Vitest + cargo-llvm-cov, enforced by .github/workflows/ci-lite.yml).

Related

Implementation Plan

Triage Assessment

Proposed Scope

  • Core Rust agent harness: assemble_turn_harness in src/openhuman/agent/.
  • ContractGateMiddleware — a single harness middleware replacing per-surface gating.
  • Transcript-derived presence using [contract-gate:<digest>:<key>] markers with XXH3-64 payload digest.
  • Full-schema discovery tools pre-credit their contracts.
  • Remove fix(composio): gate per-action tools on their full contract (#4853) #4995's composio contract_gate hookup (module retained, tracked for removal).
  • Kill switch: OPENHUMAN_CONTRACT_GATE=0.

Implementation Steps

  1. Implement ContractGateMiddleware in src/openhuman/agent/harness/ — evaluate presence from transcript markers before each model call.
  2. Wire into assemble_turn_harness — gate composio_execute, mcp_registry_tool_call, and run_workflow.
  3. Integrate XXH3-64 digest on delivered contracts for integrity verification.
  4. Pre-credit full-schema discovery tools (describe_workflow, mcp_registry_list_tools, composio_list_tools).
  5. Unify per-action Composio onto the middleware; remove composio::contract_gate hookup.
  6. Ensure feature-gate safety: flows/skills/mcp off → gate degrades to pass-through.

Verification

  • Existing tests in tests/json_rpc_e2e.rs and composio/contract gate tests.
  • Both-ways feature-gate tests (compiles with features off).
  • Coverage gate: cargo-llvm-cov diff coverage >= 80%.

Risks and Open Questions

  • Risk: transcript-derived markers could interfere with prompt formatting if models echo them back. Mitigation: markers are tool-role messages, not user/assistant turns, so models do not see them as instructions.
  • Open question: whether the composio::contract_gate module should be deleted outright rather than left in place.

Acceptance Criteria

  • As listed in the issue body (six acceptance checkboxes).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureNet-new user-facing capability or product behavior.rust-coreCore Rust runtime in src/: CLI, core_server, shared infrastructure.

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions