Skip to content

feat(tools): tool dependency graph for sequential tool availability#2059

Merged
bug-ops merged 2 commits intomainfrom
issue-2024-tool-dependency-graph
Mar 20, 2026
Merged

feat(tools): tool dependency graph for sequential tool availability#2059
bug-ops merged 2 commits intomainfrom
issue-2024-tool-dependency-graph

Conversation

@bug-ops
Copy link
Owner

@bug-ops bug-ops commented Mar 20, 2026

Summary

Implements issue #2024 — per-tool requires (hard gate) and prefers (soft score boost) dependency rules so tools can declare ordering constraints without hardcoding execution sequences.

  • ToolDependencyGraph in zeph-tools: DFS cycle detection clears requires for all cycle participants; apply() composable post-filter step; filter_tool_names() for iteration-1+ gating; preference boost capped at max_total_boost
  • Deadlock fallback (CRIT-01): when all non-always-on tools would be blocked by unmet requires, gates are disabled for that turn so the agent is never fully stalled
  • DFS cycle detection (CRIT-02): back-edge detection with InProgress/Done state tracking; all nodes in the detected cycle path have requires cleared
  • apply() as composable post-filter (HIGH-03): separated from filter() signature; called after filter() in assembly.rs
  • max_total_boost cap (HIGH-04): min(boost_per_dep * met_count, max_total_boost); default 0.20
  • TAFC ordering (MED-04): dep_graph.apply() called after TAFC augmentation in rebuild_system_prompt()
  • completed_tool_ids: HashSet<String> in Agent, cleared in clear_history(), populated on successful tool completion in native.rs
  • Config: [tools.dependencies] with enabled, boost_per_dep (0.15), max_total_boost (0.20), rules map

Test plan

  • ~25 unit tests in schema_filter.rs: cycle detection, deadlock fallback, boost cap, always-on bypass, multi-dep gates, filter_tool_names
  • cargo +nightly fmt --check — clean
  • cargo clippy --workspace --features full -- -D warnings — clean
  • cargo nextest run --config-file .github/nextest.toml --workspace --features full --lib --bins — 6103 tests passed
  • Synced with origin/main before push

Closes #2024

@github-actions github-actions bot added enhancement New feature or request size/XL Extra large PR (500+ lines) documentation Improvements or additions to documentation rust Rust code changes core zeph-core crate and removed size/XL Extra large PR (500+ lines) labels Mar 20, 2026
@bug-ops bug-ops enabled auto-merge (squash) March 20, 2026 16:49
@bug-ops bug-ops disabled auto-merge March 20, 2026 16:51
@github-actions github-actions bot added the size/XL Extra large PR (500+ lines) label Mar 20, 2026
bug-ops added 2 commits March 20, 2026 19:37
…2024)

Adds `requires` (hard gate) and `prefers` (soft score boost) per-tool
dependency rules in `[tools.dependencies]` config block.

- `ToolDependencyGraph` with DFS cycle detection: all cycle participants
  have `requires` cleared to prevent permanent deadlock
- Deadlock fallback: when all non-always-on tools would be blocked by
  unmet dependencies, gates are disabled for the current turn
- `apply()` as a composable post-filter step separate from `filter()`
- Preference boost capped at `max_total_boost` to prevent score inflation
- `completed_tool_ids: HashSet<String>` tracks successful completions
  session-scoped, cleared on `/clear`
- Dependency gates applied after TAFC augmentation (MED-04)
- Always-on and name-mentioned tools bypass hard dependency gates
- Iteration 1+ in native tool loop re-applies hard gates via
  `filter_tool_names()` with deadlock fallback
- Config: `[tools.dependencies]` with `enabled`, `boost_per_dep` (0.15),
  `max_total_boost` (0.20), `rules` map per tool
- ~25 unit tests covering cycle detection, deadlock fallback, boost cap,
  always-on bypass, and multi-dep gates
)

HIGH-01: detect_cycles() was marking all DFS ancestors of a cycle as
cycled, unnecessarily clearing `requires` for tools that only lead to
a cycle but are not part of it. Fixed by searching the stack for the
cycle entry point and only marking nodes from that position onward.

HIGH-02: NameMentioned tools were bypassing hard dependency gates,
allowing users to force access to gated tools by mentioning their name
in a query. Fixed by restricting gate bypass to AlwaysOn tools only.
NameMentioned tools now respect `requires` constraints.

Also adds multi-turn integration tests (task #4):
- Linear 2-step and 3-step dependency chains
- Multi-requires AND gate (both prerequisites needed)
- Preference boost accumulation across turns
- filter_tool_names unlock/gate semantics
- Separate integration test file: crates/zeph-tools/tests/dependency_chains.rs

Regression tests added for both HIGH findings.
@bug-ops bug-ops force-pushed the issue-2024-tool-dependency-graph branch from 2cef432 to 0a93ca3 Compare March 20, 2026 18:37
@bug-ops bug-ops enabled auto-merge (squash) March 20, 2026 18:37
@bug-ops bug-ops merged commit 47cd89b into main Mar 20, 2026
25 checks passed
@bug-ops bug-ops deleted the issue-2024-tool-dependency-graph branch March 20, 2026 18:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core zeph-core crate documentation Improvements or additions to documentation enhancement New feature or request rust Rust code changes size/XL Extra large PR (500+ lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

research(tools): tool dependency graph for sequential tool availability

1 participant