Skip to content

Support session state interpolation in SKILL.md via adk_inject_state #5404

@Koichi73

Description

@Koichi73

🔴 Required Information

Is your feature request related to a specific problem?

I want SKILL.md bodies to reference session state variables directly, the same way LlmAgent.instruction already supports {var} interpolation.

Right now, the only way to surface state values inside a skill is to define a custom tool, pass it through SkillToolset(additional_tools=[...]), and instruct the model to call that tool from within the skill. This forces every SKILL.md author to write boilerplate tools just to read a value that the agent already has access to. Agent instructions get {var} for free; skills do not.

Describe the Solution You'd Like

Enable the same {var} / {var?} / {artifact.name} interpolation inside SKILL.md, opt-in per skill via a frontmatter flag so existing SKILL.md files are not affected.

---
name: weather-skill
description: A skill that provides weather information.
metadata:
  adk_inject_state: true
---

The user prefers temperatures in {temperature_unit}.
Latest location we queried: {last_location?}.
...

When adk_inject_state: true, LoadSkillTool interpolates the skill body using the existing instructions_utils.inject_session_state helper before returning it to the model. Same syntax, same semantics, same optional-marker behavior as LlmAgent.instruction.

If adk_inject_state is absent or false, behavior is identical to today.

Impact on your work

Without this, every skill that needs to reference user preferences, conversation context, or any other state value has to ship its own "getter" tool. That is extra code on the application side and an extra LLM roundtrip at runtime. With this feature, reading state from a skill becomes a one-line declarative change — matching the ergonomics that LlmAgent.instruction already offers.

Willingness to contribute

Yes. Implementation is ready: https://github.com/Koichi73/adk-python/tree/feat/skill-md-inject-state


🟡 Recommended Information

Describe Alternatives You've Considered

  1. Custom tool via additional_tools (status quo): works but requires one function per state key and at least one additional tool call per invocation.
  2. Always-on interpolation: would break any existing SKILL.md that contains {...} as literal content. Opt-in avoids this compatibility risk entirely.
  3. New ContextProvider abstraction on SkillToolset: more flexible, but larger surface for what is really just "read from session state". The existing inject_session_state path is a perfect fit.

Proposed API / Implementation

Minimal changes, reusing existing ADK utilities:

  • src/google/adk/skills/models.py — extend Frontmatter._validate_metadata to accept adk_inject_state: bool.
  • src/google/adk/tools/skill_toolset.py — in LoadSkillTool.run_async, if the activated skill's frontmatter has adk_inject_state: true, run instructions_utils.inject_session_state(skill.instructions, ReadonlyContext(tool_context._invocation_context)) before returning.

Pseudocode:

instructions = skill.instructions
if skill.frontmatter.metadata.get("adk_inject_state"):
    instructions = await instructions_utils.inject_session_state(
        instructions,
        ReadonlyContext(tool_context._invocation_context),
    )
return {
    "skill_name": skill_name,
    "instructions": instructions,
    "frontmatter": skill.frontmatter.model_dump(),
}

No public API is changed; the new behavior is strictly additive and gated on an opt-in metadata flag.

Additional Context

This is the read side of state ↔ SKILL.md integration. The write side (an output_key-like facility for skills) will be filed as a separate issue and PR so each concern can be reviewed independently.

Metadata

Metadata

Assignees

Labels

tools[Component] This issue is related to tools

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions