Skip to content

Implement Phase 4 reasoning trigger gate with cooldown#137

Open
dilshadalikhan2004 wants to merge 2 commits into
Devnil434:mainfrom
dilshadalikhan2004:feat/reasoning-trigger-gate
Open

Implement Phase 4 reasoning trigger gate with cooldown#137
dilshadalikhan2004 wants to merge 2 commits into
Devnil434:mainfrom
dilshadalikhan2004:feat/reasoning-trigger-gate

Conversation

@dilshadalikhan2004
Copy link
Copy Markdown
Contributor

@dilshadalikhan2004 dilshadalikhan2004 commented May 29, 2026

Summary

Implemented the Phase 4 reasoning trigger gate to prevent unnecessary VLM/LLM invocations by evaluating track sequences before triggering reasoning.

Changes

  • Added should_trigger_reasoning(seq: TrackSequence) -> bool

  • Added in-memory cooldown tracking

  • Added reset_cooldown(track_id)

  • Added suspicious action detection for:

    • LINGERING
    • NEAR_KEYPAD
    • REPEATED_APPROACH
  • Added dwell threshold validation using centralized settings

  • Updated trigger tests to use TrackSequence

Tests

Added/updated tests covering:

  • Returns False without zone
  • Returns False below dwell threshold
  • Returns False without suspicious actions
  • Returns True for valid suspicious sequence
  • Returns False during cooldown
  • Cooldown reset allows re-trigger

All trigger tests pass successfully.

Note

The existing trigger tests were based on the older TrackLifecycleEvent interface. They were updated to align with the TrackSequence-based API specified in Issue #42.

Summary by CodeRabbit

  • New Features

    • Updated default detection thresholds for lingering, movement, and keypad proximity (including keypad center coordinates) for more accurate and tunable behavior.
  • Refactor

    • Reworked trigger logic to evaluate whole track sequences, improving reasoning accuracy and preserving per-track cooldown behavior for more reliable alerts.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

Caution

Review failed

Failed to post review comments

📝 Walkthrough

Walkthrough

This PR refactors the memory trigger reasoning-gate API from a TrackLifecycleEvent-plus-action-strings pattern to a TrackSequence-based pattern, updates action-classifier configuration defaults, and revises tests to use TrackSequence/ActionHint with fixtures and helpers.

Changes

Memory Trigger API and Test Refactoring

Layer / File(s) Summary
Configuration Settings Extension
libs/config/settings.py
Introduces action-classifier threshold fields (lingering_threshold_sec, movement_threshold_px, near_keypad_dist_px, keypad_center_x, keypad_center_y) and reformats model_config into multi-line form.
Trigger Logic Refactoring
services/memory/trigger.py
Migrates should_trigger_reasoning to accept TrackSequence instead of TrackLifecycleEvent + suspicious_actions set; updates SUSPICIOUS_ACTIONS to use ActionHint enum members; removes negative-threshold validation; cooldown now keys off seq.track_id.
Test Suite Update and Fixtures
tests/test_trigger.py
Adds fixed_reasoning_gate_config fixture to pin settings; introduces make_sequence() helper to build test inputs with parametrized dwell, zones, track id, and action hint; updates all test assertions to call the new should_trigger_reasoning(seq) signature.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

  • Devnil434/Eagle#60: Also modifies services/memory/trigger.py, tests/test_trigger.py, and libs/config/settings.py reasoning-trigger paths; this PR further refactors the API from TrackLifecycleEvent/strings to TrackSequence/ActionHint.

Suggested labels

gssoc:approved

Poem

🐰 I nudged the sequence, gave actions a hint,
Thresholds tucked neatly, no more vague squint,
Cooldowns remembered by each track's ID,
Tests hop in order, deterministic and keyed,
A little rabbit cheers: logic aligned—what a sprint!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main purpose of the PR: implementing a Phase 4 reasoning trigger gate with cooldown functionality, which is the primary change across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
services/memory/trigger.py (1)

11-11: 💤 Low value

_reasoning_cooldowns grows unbounded and is unsynchronized.

Entries are added on every successful trigger (Line 66) and only removed via reset_cooldown. If reasoning fails or reset_cooldown is never called for some tracks, the dict accumulates one entry per track_id for the process lifetime. Additionally, the check-then-set on Lines 60-66 is not atomic, so concurrent invocations for the same track_id could both trigger. If the pipeline ever processes tracks across threads, consider a lock and/or periodic eviction of stale entries.

Also applies to: 57-66

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/memory/trigger.py` at line 11, _reasoning_cooldowns currently grows
unbounded and is updated without synchronization; make access atomic and evict
stale entries by introducing a lock (e.g., _reasoning_cooldowns_lock) and a TTL
constant (e.g., REASONING_COOLDOWN_TTL) and wrap all reads/writes (checks,
setting on trigger, and reset_cooldown) to _reasoning_cooldowns in that lock so
the check-then-set around the trigger is atomic; additionally, on each access
(or periodically) prune entries older than TTL so failed or forgotten track_ids
don't accumulate, and ensure failures also clear their entries via
reset_cooldown.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@services/memory/trigger.py`:
- Around line 43-45: The current gating in should_trigger_reasoning only ensures
seq.zones_visited is non-empty so it fires for any visited zone; either update
the function docstring to state it intentionally triggers on any visited zone,
or change the gating to require an intersection with the restricted-zone set
(e.g., filter seq.zones_visited against the restricted zones provided by Memory
or a RESTRICTED_ZONES constant) before returning True; locate
should_trigger_reasoning in services/memory/trigger.py and use the same
restricted-zone identifier used in services/memory/memory.py (or the
Memory.restricted_zones attribute) to perform the filtered check.

---

Nitpick comments:
In `@services/memory/trigger.py`:
- Line 11: _reasoning_cooldowns currently grows unbounded and is updated without
synchronization; make access atomic and evict stale entries by introducing a
lock (e.g., _reasoning_cooldowns_lock) and a TTL constant (e.g.,
REASONING_COOLDOWN_TTL) and wrap all reads/writes (checks, setting on trigger,
and reset_cooldown) to _reasoning_cooldowns in that lock so the check-then-set
around the trigger is atomic; additionally, on each access (or periodically)
prune entries older than TTL so failed or forgotten track_ids don't accumulate,
and ensure failures also clear their entries via reset_cooldown.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 706987e1-7a7a-41b2-896e-ae8f59ea75a6

📥 Commits

Reviewing files that changed from the base of the PR and between 3c9175c and 3035870.

📒 Files selected for processing (3)
  • libs/config/settings.py
  • services/memory/trigger.py
  • tests/test_trigger.py

Comment on lines +43 to 45
# Zone check
if not seq.zones_visited:
return False
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect how zones_visited / zones_key is populated to see whether it is restricted-only.
rg -nP -C4 '\bzones_visited\b' --type=py
rg -nP -C4 '_zones_key|zones_present|restricted' --type=py

Repository: Devnil434/Eagle

Length of output: 50371


Fix restricted-zone gating in should_trigger_reasoning

  • services/memory/trigger.py only checks that seq.zones_visited is non-empty (if not seq.zones_visited: return False), so it will fire for any visited zone.
  • services/memory/memory.py populates zones_visited by collecting event.zone values with no restricted-only filtering; tests/test_memory.py::test_zones_visited_populated shows "safe_corridor" and "restricted_door" both ending up in seq.zones_visited.
    Update the docstring/intent to match “any visited zone” or filter seq.zones_visited against the restricted-zone set before allowing the trigger to proceed.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/memory/trigger.py` around lines 43 - 45, The current gating in
should_trigger_reasoning only ensures seq.zones_visited is non-empty so it fires
for any visited zone; either update the function docstring to state it
intentionally triggers on any visited zone, or change the gating to require an
intersection with the restricted-zone set (e.g., filter seq.zones_visited
against the restricted zones provided by Memory or a RESTRICTED_ZONES constant)
before returning True; locate should_trigger_reasoning in
services/memory/trigger.py and use the same restricted-zone identifier used in
services/memory/memory.py (or the Memory.restricted_zones attribute) to perform
the filtered check.

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.

2 participants