feat(skills): Allow opt-in session state injection in skill instructions#5974
feat(skills): Allow opt-in session state injection in skill instructions#5974lwangverizon wants to merge 1 commit into
Conversation
Agent instructions support injecting dynamic session state via
`{var_name}`, `{artifact.file_name}`, and `{optional?}` templates, but
skill instructions returned by `load_skill` were emitted verbatim, so a
skill body could not reference per-session state.
Add an opt-in frontmatter flag `adk_inject_session_state` (mirroring the
existing `adk_additional_tools` metadata convention). When set to true,
`LoadSkillTool` routes the skill instructions through the existing
`inject_session_state` utility before returning them. The flag defaults
to disabled so that literal braces in skill markdown (code samples,
JSON, templates) are preserved and existing skills are unaffected.
A missing required variable surfaces a `STATE_INJECTION_ERROR` tool
result rather than raising, consistent with the toolset's other error
responses.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
|
Response from ADK Triaging Agent Hello @lwangverizon, thank you for creating this PR! It looks like a great addition to the ADK skill features. To help us move forward with reviewing and merging your contributions, could you please address the following items from our contribution guidelines:
This information will help reviewers verify and understand your change more efficiently. Thanks! |
Add an opt-in frontmatter metadata flag `adk_inject_session_state`
(mirroring the existing `adk_additional_tools` convention). When set to
true, `LoadSkillTool` routes the skill instructions through the existing
`inject_session_state` utility before returning them, so a skill body can
reference dynamic session state (`{var_name}`, `{artifact.file_name}`,
`{optional?}`) the same way a system prompt can.
Defaults to disabled so literal braces in skill markdown are preserved
and existing skills are unaffected. A missing required variable returns a
`STATE_INJECTION_ERROR` tool result rather than raising.
Backport of upstream PR google#5974 (issue google#5973), adapted to
the vzgpt-core skill activation logic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Link to Issue or Description of Change
1. Link to an existing issue:
Problem:
Agent instructions support injecting dynamic session state via template
variables —
{var_name},{app:var},{artifact.file_name}, and the optional{var?}form — throughinject_session_state(seeflows/llm_flows/instructions.py). Skill instructions returned by theload_skilltool, however, are emitted verbatim. As a result a skill'sSKILL.mdbody cannot reference per-session state the way a system prompt can,which is inconvenient for skills that need to adapt to the current user,
artifacts, or session context.
Solution:
Add an opt-in frontmatter metadata flag
adk_inject_session_state, mirroringthe existing
adk_additional_toolsmetadata convention. When set totrue,LoadSkillToolroutes the skill instructions through the existinginject_session_stateutility before returning them; otherwise behavior isunchanged.
The flag defaults to disabled on purpose: skill markdown routinely contains
literal braces (code samples, JSON, templates), and
inject_session_stateraises
KeyErroron an unknown{identifier}. Making injection always-on wouldbreak existing skills, so authors must explicitly opt in per skill. This keeps
the change fully backward-compatible.
A missing required variable returns a
STATE_INJECTION_ERRORtool result(rather than raising), consistent with the toolset's other error responses and
its
_detect_error_in_responsetelemetry hook.Example
SKILL.md:Scope is limited to
load_skillinstructions;load_skill_resourcecontent isintentionally out of scope and can follow the same pattern later if desired.
Files changed:
src/google/adk/skills/models.py— validateadk_inject_session_stateis abool; document the key in the
metadataattribute docstring.src/google/adk/tools/skill_toolset.py— inject session state into skillinstructions when the flag is set; return
STATE_INJECTION_ERRORon a missingrequired variable.
Testing Plan
Unit Tests:
New tests:
tests/unittests/tools/test_skill_toolset.pytest_load_skill_no_injection_by_default— braces preserved verbatim whenthe flag is absent (backward-compat).
test_load_skill_injects_session_state_when_enabled—{user_name}substituted from state when enabled.
test_load_skill_injection_optional_var_empty—{var?}missing → emptystring.
test_load_skill_injection_missing_required_var_returns_error— missingrequired var →
STATE_INJECTION_ERROR(no crash).tests/unittests/skills/test_models.pytest_metadata_adk_inject_session_state_boolandtest_metadata_adk_inject_session_state_invalid_type— validator coverage.(
test_instructions_utils.pyincluded to confirm the shared injection utilityis unchanged.)
Manual End-to-End (E2E) Tests:
Define a skill with
adk_inject_session_state: truewhoseSKILL.mdbodyreferences
{user_name}, seed the session state withuser_name, and confirmthe
load_skilltool result returns the resolved text. Omit the flag (or thestate key for a required variable) to confirm the verbatim /
STATE_INJECTION_ERRORpaths respectively.
Checklist