Skip to content

refactor: intent layers gate via intent context, not enable/disable#427

Merged
JarbasAl merged 8 commits into
devfrom
feat/intent-layers-context
Jun 26, 2026
Merged

refactor: intent layers gate via intent context, not enable/disable#427
JarbasAl merged 8 commits into
devfrom
feat/intent-layers-context

Conversation

@JarbasAl

@JarbasAl JarbasAl commented Jun 25, 2026

Copy link
Copy Markdown
Member

Modernizes IntentLayers to gate intents via the session's intent context instead of globally enabling/disabling them — so layer gating is per-session (concurrent multi-session safe).

Standalone + backwards-compatible: the public decorator API (@layer_intent/@enables_layer/@disables_layer/@replaces_layer/@removes_layer/@resets_layers) and the IntentLayers methods are preserved; disable() aliases reset(), is_active() gains an optional session=. Existing consumers need no changes.

Game-skill + OCP-playback session-awareness were split out to #428 (stacked on this). OCPCommonPlaybackSkill deprecation is #423.

488 tests pass (incl. a back-compat regression for the legacy layer API).

🤖 Generated with Claude Code

Redesign IntentLayers so a layer maps to an intent-context token instead
of mutating the global enabled/disabled intent set.

- activate_layer -> skill.set_context(<layer token>)
- deactivate_layer -> skill.remove_context(<layer token>)
- reset() (kept aliased as disable()) removes every active layer context

`@layer_intent` now injects the layer context token as a `.require()` on
the IntentBuilder, so the intent only validates while its layer is active.
Intents stay registered for the skill lifetime; gating is per-session via
adapt context, with no detach/attach churn.

resets_layers() now calls reset(); the enable_intent/disable_intent paths
are gone from the layer machinery.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@JarbasAl, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 6 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 89fac21f-b55e-4988-bfa7-c0ef89434e8d

📥 Commits

Reviewing files that changed from the base of the PR and between 9234a41 and 31a8bc8.

📒 Files selected for processing (6)
  • ovos_workshop/decorators/layers.py
  • ovos_workshop/skills/ovos.py
  • pyproject.toml
  • requirements/test.txt
  • test/unittests/skills/test_intent_layers_e2e.py
  • test/unittests/test_decorators_layers_extended.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/intent-layers-context

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.

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Checking back in with the latest test results. 📡

I've aggregated the results of the automated checks for this PR below.

📋 Repo Health

Checking if the repo is following its diet. 🥗

✅ All required files present.

Latest Version: 8.3.0a1

ovos_workshop/version.py — Version file
README.md — README
LICENSE — License file
pyproject.toml — pyproject.toml
⚠️ setup.py — setup.py
CHANGELOG.md — Changelog
ovos_workshop/version.py has valid version block markers

🔍 Lint

Checking if we've met all our check criteria. ✅

ruff: issues found — see job log

🔒 Security (pip-audit)

Checking for any insecure data transmissions. 📡

✅ No known vulnerabilities found (72 packages scanned).

⚖️ License Check

Checking if the licenses are compatible with OVOS. 🧩

✅ No license violations found.

Policy: Apache 2.0 (universal donor). StrongCopyleft / NetworkCopyleft / WeakCopyleft / Other / Error categories fail. MPL allowed.

🔨 Build Tests

The build process has successfully terminated. 🏁

Python Build Install Tests
3.10 ⚠️
3.11
3.12
3.13
3.14

❌ 3.10: Install OK, tests failed
Check job logs for details.


Keeping the bits in line, one repo at a time. 🔣

…h probe

Make ConversationalGameSkill work with the new context-gated layers:

- OVOSGameSkill now also inherits ConversationalSkill so the converse
  ping/request bus handlers are actually wired for game skills (they were
  not, so converse never ran for games).
- Add OVOSSkill.skill_will_match(): a read-only probe over
  intent.service.intent.get that reports whether one of THIS skill's
  intents would match an utterance under the current session context.
  Supports exclude_pipeline so a conversing skill can skip the converse
  stage and avoid re-entrancy.
- ConversationalGameSkill.can_converse() returns True only while playing
  AND no context-gated layer intent would match (so layer intents are
  handled by adapt, not swallowed by converse). converse() uses the same
  probe. calc_intent() now ignores non-intent-parser pipeline results.
- on_play_game restart semantics doc fix in the game base.

Add a 4-layer demo skill e2e (ovoscope MiniCroft / FakeBus) proving the
layer mechanism: utterances advance layer0->layer3, only the active
layer's intent matches at each step (others are gated off via missing
context), always-on intents match throughout, and reset removes the
context so layer intents stop matching.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…on aware)

OCP tracks player state per session, so game/playback skills must too.

- OVOSCommonPlaybackSkill: _playing/_paused Events -> per-session sets
  (_playing_sessions/_paused_sessions) keyed by SessionManager.get(msg)
  .session_id. New get_session_id(), is_playing_in/is_paused_in,
  playing_sessions; is_playing/is_paused properties now resolve the current
  session. OCP play/pause/resume/stop handlers key state by session and reply
  with message.reply so the session round-trips.
- OVOSGameSkill.stop_game is per-session; on_pause_game/on_resume_game no
  longer mutate paused state (the framework does, per session);
  on_game_command(self, utterance, lang, message=None) - the message (and thus
  session) is now passed so games can key per-session state.
- IntentLayers.is_active(layer, session=None) reads the layer's context token
  from the session (the per-session source of truth), falling back to the
  skill-level active_layers when no session is resolvable. This makes layer
  gating correct under concurrent multi-session play.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
JarbasAl and others added 4 commits June 26, 2026 01:45
- common_play: assert per-session playback state (no playing/paused
  sessions on init) instead of the removed _playing/_paused Event objects
- intent_layers_e2e: restore the global SessionManager.bus in tearDownClass
  so the stopped MiniCroft bus does not leak into get_response/killable
  intent tests sharing the class-level SessionManager

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The intent-layers e2e test drives a live ADAPT pipeline via MiniCroft; CI
installs only the declared test extras, where ovos-adapt-parser (which
provides the ovos-adapt-pipeline-plugin matcher) was missing, so the
pipeline matched nothing ('Unknown pipeline matcher'). Add it to both the
[test] extra and requirements/test.txt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Stable ovos-adapt-parser 1.0.9 caps ovos-workshop<8.0.0, which conflicts
with this branch (8.3.0a1) and made the install unresolvable in CI.
1.3.1a1 relaxes the cap to <9.0.0; pin it as the floor (prerelease floor
pin) so pip resolves it without --pre.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ove to a stacked PR

IntentLayers stays standalone and backwards-compatible for decorator consumers
(disable() aliases reset(); all decorators + methods preserved). The session-aware
game-skill + OCPCommonPlayback changes move to feat/gameskill-and-ocp-deprecation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@JarbasAl JarbasAl changed the title feat!: intent layers gate via intent context, not enable/disable refactor: intent layers gate via intent context, not enable/disable Jun 26, 2026
…s context

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@JarbasAl JarbasAl merged commit 0ce90f5 into dev Jun 26, 2026
10 of 11 checks passed
@JarbasAl JarbasAl deleted the feat/intent-layers-context branch July 1, 2026 12:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant