Skip to content

feat(skills): Allow opt-in session state injection in skill instructions#5974

Open
lwangverizon wants to merge 1 commit into
google:mainfrom
lwangverizon:feat/skill-session-state-injection
Open

feat(skills): Allow opt-in session state injection in skill instructions#5974
lwangverizon wants to merge 1 commit into
google:mainfrom
lwangverizon:feat/skill-session-state-injection

Conversation

@lwangverizon
Copy link
Copy Markdown
Contributor

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 — through inject_session_state (see
flows/llm_flows/instructions.py). Skill instructions returned by the
load_skill tool, however, are emitted verbatim. As a result a skill's
SKILL.md body 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, 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; otherwise behavior is
unchanged.

The flag defaults to disabled on purpose: skill markdown routinely contains
literal braces (code samples, JSON, templates), and inject_session_state
raises KeyError on an unknown {identifier}. Making injection always-on would
break 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_ERROR tool result
(rather than raising), consistent with the toolset's other error responses and
its _detect_error_in_response telemetry hook.

Example SKILL.md:

---
name: greeter
description: Greets the current user by name.
metadata:
  adk_inject_session_state: true
---
Greet {user_name} warmly.{optional_note?}

Scope is limited to load_skill instructions; load_skill_resource content is
intentionally out of scope and can follow the same pattern later if desired.

Files changed:

  • src/google/adk/skills/models.py — validate adk_inject_session_state is a
    bool; document the key in the metadata attribute docstring.
  • src/google/adk/tools/skill_toolset.py — inject session state into skill
    instructions when the flag is set; return STATE_INJECTION_ERROR on a missing
    required variable.

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

New tests:

  • tests/unittests/tools/test_skill_toolset.py
    • test_load_skill_no_injection_by_default — braces preserved verbatim when
      the 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 → empty
      string.
    • test_load_skill_injection_missing_required_var_returns_error — missing
      required var → STATE_INJECTION_ERROR (no crash).
  • tests/unittests/skills/test_models.py
    • test_metadata_adk_inject_session_state_bool and
      test_metadata_adk_inject_session_state_invalid_type — validator coverage.
$ pytest tests/unittests/tools/test_skill_toolset.py \
         tests/unittests/skills/test_models.py \
         tests/unittests/utils/test_instructions_utils.py -q
146 passed

(test_instructions_utils.py included to confirm the shared injection utility
is unchanged.)

Manual End-to-End (E2E) Tests:

Define a skill with adk_inject_session_state: true whose SKILL.md body
references {user_name}, seed the session state with user_name, and confirm
the load_skill tool result returns the resolved text. Omit the flag (or the
state key for a required variable) to confirm the verbatim / STATE_INJECTION_ERROR
paths respectively.

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 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.

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>
@google-cla
Copy link
Copy Markdown

google-cla Bot commented Jun 5, 2026

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.

@adk-bot adk-bot added the tools [Component] This issue is related to tools label Jun 5, 2026
@adk-bot
Copy link
Copy Markdown
Collaborator

adk-bot commented Jun 5, 2026

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:

  1. Sign the Contributor License Agreement (CLA): It appears that the cla/google status check has failed. Please visit https://cla.developers.google.com/ to sign or update your agreement.
  2. Provide Logs or Screenshots for Manual Testing: While your description of the manual end-to-end testing plan is very helpful, please provide the actual console logs, output, or screenshots showing the successful results of your E2E test once the fix is applied.

This information will help reviewers verify and understand your change more efficiently. Thanks!

lwangverizon added a commit to lwangverizon/adk-python that referenced this pull request Jun 5, 2026
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tools [Component] This issue is related to tools

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support session state injection in skill instructions (like system prompt)

2 participants