You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(skills): inject session state into SKILL.md via adk_inject_state
Merge #5405
### Link to Issue or Description of Change
- Closes: #5404
**Problem:** SKILL.md bodies cannot reference session state the same way `LlmAgent.instruction` can. Today the only way to surface a state value inside a skill is to register a custom getter tool through `SkillToolset(additional_tools=[...])` and tell the model to call it. That is boilerplate for a capability the agent already has.
**Solution:** Reuse the existing `instructions_utils.inject_session_state` helper from `LoadSkillTool`. When a skill opts in with `metadata.adk_inject_state: true` in its frontmatter, the skill body is interpolated with the same `{var}` / `{var?}` / `{artifact.name}` syntax that `LlmAgent.instruction` supports. The feature is strictly additive and gated on an opt-in flag, so existing SKILL.md files are unaffected.
### Testing Plan
**Unit Tests:**
- [x] I have added or updated unit tests for my change.
- [x] All unit tests pass locally.
Added to `tests/unittests/tools/test_skill_toolset.py`:
- `test_load_skill_run_async_injects_state_when_opt_in`
- `test_load_skill_run_async_skips_injection_when_opt_out`
- `test_load_skill_run_async_skips_injection_when_metadata_absent`
Added to `tests/unittests/skills/test_models.py`:
- `test_metadata_adk_inject_state_bool`
- `test_metadata_adk_inject_state_rejected_as_string`
Existing mock fixtures for `skill1` / `skill2` frontmatter now explicitly set `metadata = {}`, documenting the default and preventing autospec-mock leakage into the new opt-in check.
`pytest` summary:
```
$ pytest tests/unittests/tools/test_skill_toolset.py tests/unittests/skills/test_models.py
111 passed, 7 warnings in 11.39s
```
**Manual End-to-End (E2E) Tests:**
1. In a skill directory, add `metadata: {adk_inject_state: true}` to `SKILL.md` frontmatter and reference a state variable in the body, e.g. `The user prefers {temperature_unit?}.`
2. Seed session state with `session.state["temperature_unit"] = "celsius"` before the agent runs.
3. Run the agent (`adk run` or `adk web`) and trigger the skill. The `load_skill` tool response now contains the instructions with `{temperature_unit}` expanded to `celsius`.
4. Remove or set `adk_inject_state: false` and re-run — the same SKILL.md returns the literal `{temperature_unit?}` string, confirming backward compatibility.
### Checklist
- [x] I have read the [CONTRIBUTING.md](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) document.
- [x] I have performed a self-review of my own code.
- [x] I have commented my code, particularly in hard-to-understand areas.
- [x] I have added tests that prove my fix is effective or that my feature works.
- [x] New and existing unit tests pass locally with my changes.
- [x] I have manually tested my changes end-to-end.
- [x] Any dependent changes have been merged and published in downstream modules.
### Additional context
This is the read side of a two-part effort to connect SKILL.md with session state. A follow-up PR will propose an `output_key`-style facility for writing state from a skill. Splitting the two keeps each review small and focused.
Co-authored-by: Haran Rajkumar <haranrk@google.com>
COPYBARA_INTEGRATE_REVIEW=#5405 from Koichi73:feat/skill-md-inject-state 44067c2
PiperOrigin-RevId: 936248442
0 commit comments