Skip to content

feat(tools): add rolling window for activated skills in SkillToolset#5745

Open
lwangverizon wants to merge 1 commit into
google:mainfrom
lwangverizon:feat/skill-rolling-window-clean
Open

feat(tools): add rolling window for activated skills in SkillToolset#5745
lwangverizon wants to merge 1 commit into
google:mainfrom
lwangverizon:feat/skill-rolling-window-clean

Conversation

@lwangverizon
Copy link
Copy Markdown
Contributor

Link to Issue or Description of Change

2. Or, if no issue exists, describe the change:

Problem:
In long-running sessions, the SkillToolset accumulates activated skills unboundedly. Each load_skill call adds tools to the session state, growing the tool context sent to the LLM indefinitely. This can degrade LLM performance as the function declarations list grows, increase token consumption, and in extreme cases exceed context window limits.

Unlike AutoGen (static tools at construction) and LangGraph (static tool binding with dynamic routing), ADK's skill system allows mid-session tool expansion — which is powerful but requires bounds.

Solution:
Add an optional max_activated_skills parameter to SkillToolset that enforces a rolling window (LRU eviction) on concurrently activated skills per agent.

Key design decisions:

  • LRU semantics: Re-loading an already-active skill promotes it to the most-recent position (no duplication)
  • Oldest-first eviction: When the limit is exceeded, the oldest activated skills are evicted from session state
  • Backward compatible: Default is None (no limit), preserving existing behavior
  • Minimal footprint: ~15 lines of logic in LoadSkillTool.run_async, no new dependencies

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.
100 passed, 6 warnings in 10.83s

7 new tests added covering:

  • test_max_activated_skills_evicts_oldest — verifies oldest skill is evicted when limit exceeded
  • test_max_activated_skills_keeps_recent_n — confirms only N most recent skills retained
  • test_max_activated_skills_reloading_moves_to_end — validates LRU promotion on re-load
  • test_no_max_activated_skills_unlimited — confirms backward compatibility (no limit)
  • test_evicted_skill_tools_not_resolved — verifies evicted tools are excluded from get_tools
  • test_evicted_tool_call_raises_value_error — confirms _get_tool raises ValueError for evicted tools
  • test_rolling_window_full_lifecycle_with_tool_resolution — end-to-end lifecycle test

Manual End-to-End (E2E) Tests:

Tested with a multi-skill agent using adk web — confirmed that after exceeding max_activated_skills=3, older skills are no longer available in the LLM's tool declarations, and re-loading a skill correctly promotes it.

Checklist

  • I have read the CONTRIBUTING.md document.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have manually tested my changes end-to-end.
  • Any dependent changes have been merged and published in downstream modules.

Additional context

Comparison with other frameworks:

  • AutoGen: Tools are static at agent construction — no mid-session expansion possible
  • LangGraph: Static tool binding with dynamic routing via graph edges — no accumulation

ADK's skill system is uniquely powerful in allowing runtime tool discovery and loading, but this PR ensures it remains bounded and performant in long-running sessions.

Edge case note: If the LLM calls a tool from conversation history that was since evicted, _get_tool() in functions.py raises ValueError. This is recoverable via on_tool_error callbacks. The risk is minimal since evicted tools are removed from the next function declarations, so the LLM won't attempt to call them.

Add max_activated_skills parameter to SkillToolset that enforces a
rolling window on the number of concurrently activated skills per agent.
When the limit is exceeded, the oldest activated skills (and their
associated additional tools) are evicted from session state.

This addresses unbounded tool context growth during long-running sessions
where many skills get loaded but only recent ones are relevant.

Key changes:
- Add max_activated_skills param to SkillToolset.__init__
- Enforce LRU-style eviction in LoadSkillTool.run_async: re-loading an
  already active skill promotes it to most-recent position
- Always persist state (even for re-activations) to maintain ordering
- Default is None (no limit) for backward compatibility
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.

1 participant