Skip to content

Conversation

@caohy1988
Copy link

Summary

  • Add a sample agent demonstrating Anthropic's Agent Skills Pattern for dynamic capability discovery
  • Implements progressive disclosure: skill names/descriptions loaded initially, full content on-demand via load_skill tool
  • Includes two skills: bqml (BigQuery ML) and bq_ai_operator (managed AI functions)

Files Added

contributing/samples/bigquery_skills_demo/
├── __init__.py           # Module init
├── agent.py              # Agent with BigQuery tools and load_skill
├── skill_registry.py     # Dynamic skill discovery (Anthropic pattern)
├── skills/
│   ├── bqml/
│   │   └── SKILL.md      # BQML skill documentation
│   └── bq_ai_operator/
│       └── SKILL.md      # AI operator skill documentation
└── README.md             # Documentation

How It Works

  1. Skill Discovery: SkillRegistry scans skills/ directory for SKILL.md files
  2. YAML Frontmatter: Each SKILL.md has metadata (name, description) in YAML frontmatter
  3. Progressive Loading: Agent sees skill summaries in system prompt, calls load_skill(name) for full docs

Test Plan

  • Run adk run contributing/samples/bigquery_skills_demo locally
  • Test BQML skill with prompt: "Train a linear regression model on the penguins dataset"
  • Test AI Operator skill with prompt: "Classify BBC news articles by topic"

References

🤖 Generated with Claude Code

Add a sample agent demonstrating Anthropic's Agent Skills Pattern for
dynamic capability discovery with BigQuery ML and AI functions.

Key features:
- Dynamic skill discovery from SKILL.md files at runtime
- Progressive disclosure: skill summaries in prompt, full content on-demand
- load_skill tool for agents to request detailed skill documentation
- BQML skill: ML model training, evaluation, and prediction in SQL
- BQ AI Operator skill: AI.CLASSIFY, AI.IF, AI.SCORE managed functions

The demo is self-contained and uses existing BigQuery tools from ADK.
Skills are stored as markdown files with YAML frontmatter for metadata.

Reference: https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@google-cla
Copy link

google-cla bot commented Dec 7, 2025

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.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @caohy1988, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request adds a new sample agent that demonstrates dynamic skill discovery using Anthropic's Agent Skills Pattern. The agent is designed to efficiently manage its capabilities by initially loading only summaries of available skills (BigQuery ML and AI functions) and fetching detailed documentation on-demand when relevant to a task. This approach optimizes context usage while providing access to a rich set of BigQuery data science and AI tools.

Highlights

  • Dynamic Skill Discovery: Introduces a sample agent demonstrating Anthropic's Agent Skills Pattern for dynamic capability discovery.
  • Progressive Disclosure: Implements a progressive disclosure mechanism where skill summaries are loaded initially, and full skill content is loaded on-demand via a "load_skill" tool.
  • BigQuery Integration: Includes two new skills, "bqml" (BigQuery ML) and "bq_ai_operator" (managed BigQuery AI functions), showcasing powerful data science and AI capabilities directly within BigQuery.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@caohy1988 caohy1988 marked this pull request as draft December 7, 2025 09:21
@adk-bot
Copy link
Collaborator

adk-bot commented Dec 7, 2025

Response from ADK Triaging Agent

Hello @caohy1988, thank you for creating this PR!

Before we can review this PR, you will need to sign the Contributor License Agreement (CLA). You can find more information at https://cla.developers.google.com/.

In addition, this PR is a new feature, could you please associate a GitHub issue with this PR? If there is no existing issue, could you please create one?

Finally, could you please provide logs or screenshots of the new feature in action? This will help reviewers to understand and verify your changes.

This information will help reviewers to review your PR more efficiently. Thanks!

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an excellent sample agent demonstrating dynamic skill discovery with BigQuery. The code is well-structured and the implementation of the Anthropic Agent Skills Pattern is clear. I have a few suggestions to improve the robustness and efficiency of the skill registry, primarily around exception handling and the creation of the load_skill tool. Additionally, I've pointed out a couple of hardcoded project IDs in one of the skill definition files that should be updated to avoid confusion for users. Overall, this is a great addition.

Comment on lines 279 to 284
def load_skill(skill_name: str) -> str:
"""Load a skill from the default registry.

This is the function that should be added as a tool to the agent.
"""
return create_load_skill_tool(get_default_registry())(skill_name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current implementation of the load_skill function has two issues:

  1. Inefficiency: It calls create_load_skill_tool on every invocation, which re-creates the underlying function object unnecessarily.
  2. Incorrect Docstring: The FunctionTool in agent.py will use the docstring from this module-level load_skill function, which is generic. The more descriptive docstring intended for the agent (defined inside create_load_skill_tool) is never used. This can negatively impact the agent's ability to understand and use the tool correctly.

A better approach is to create the tool function once at the module level.

load_skill = create_load_skill_tool(get_default_registry())

Comment on lines +146 to +147
except Exception:
return None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The broad except Exception: clause catches all errors silently. This can make debugging difficult if there are issues with parsing skill files (e.g., malformed YAML, file read errors). It would be beneficial to log the exception to aid in troubleshooting, for example by adding logging.warning(f"Failed to parse skill metadata from {skill_path}: {e}") inside the except block.

Comment on lines +195 to +196
except Exception:
return None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the metadata parsing logic, this broad except Exception: clause catches all errors silently when reading a skill's content. This can hide file-related issues like permission errors. Logging the exception here would make the system more robust and easier to debug.

return "\n".join(lines)


def create_load_skill_tool(registry: SkillRegistry) -> dict[str, Any]:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The function create_load_skill_tool is type-hinted to return dict[str, Any], but it actually returns a callable function (load_skill). The type hint should be corrected to Callable[[str], str] to reflect the actual return type. You may need to import Callable from typing.

Suggested change
def create_load_skill_tool(registry: SkillRegistry) -> dict[str, Any]:
def create_load_skill_tool(registry: SkillRegistry) -> "Callable[[str], str]":

WHERE AI.IF(
description,
'This product is eco-friendly, sustainable, or environmentally conscious',
connection_id => 'us.my_ai_connection' -- Use your connection: test-project-0728-467323.us.my_ai_connection
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The example for AI.IF contains a hardcoded project ID (test-project-0728-467323). This can be misleading for users running the sample. It should be replaced with a generic placeholder or removed to match the other examples in this file.

Suggested change
connection_id => 'us.my_ai_connection' -- Use your connection: test-project-0728-467323.us.my_ai_connection
connection_id => 'us.my_ai_connection' -- Replace with your connection

WHERE AI.IF(
review_text,
'Content is appropriate and not spam',
connection_id => 'us.my_ai_connection' -- Use your connection: test-project-0728-467323.us.my_ai_connection
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The example in the complete pipeline contains a hardcoded project ID (test-project-0728-467323). This should be replaced with a generic placeholder to avoid confusion for users.

Suggested change
connection_id => 'us.my_ai_connection' -- Use your connection: test-project-0728-467323.us.my_ai_connection
connection_id => 'us.my_ai_connection' -- Replace with your connection

caohy1988 and others added 2 commits December 7, 2025 12:48
Replace persistent load_skill tool with ephemeral skill activation:
- Skills are now injected into system prompt (not conversation history)
- Add activate_skill/deactivate_skill/list_active_skills tools
- Use ADK's InstructionProvider pattern for dynamic system prompt
- Skills can be truly unloaded when no longer needed

This mirrors Claude Code's approach where skills are loaded on-demand
and can be removed to free up context space.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…r BigQuery Skills Demo

This commit enhances the BigQuery Skills Demo with:

- **Callback-based auto-activation**: Skills are automatically activated based
  on keywords in user messages via before_model_callback, eliminating the need
  for explicit LLM tool calls to manage skills
- **Auto-deactivation**: Skills are cleared after each turn via
  after_agent_callback to free up context
- **list_connections and create_connection tools**: Agents can now discover
  existing BigQuery connections and create new ones with automatic IAM grants
- **Location matching documentation**: Skills now document the critical
  requirement that connection location must match dataset location
- **bq_remote_model skill**: New skill for remote models with Vertex AI,
  including Gemini 2.5 Pro as default model and task-specific parameter
  guidance (max_output_tokens for summarization vs classification)
- **AI.SCORE tuple syntax fix**: Corrected syntax to use tuple format per
  official BigQuery documentation
- **Keywords in SKILL.md frontmatter**: Skills now define keywords that are
  used for automatic detection

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@ryanaiagent ryanaiagent self-assigned this Dec 9, 2025
caohy1988 and others added 3 commits December 9, 2025 01:52
This commit fixes the 'LlmRequest' object has no attribute 'system_instruction'
error by using the proper LlmRequest.append_instructions() API for skill injection.

Key changes:
- skill_callbacks.py: Use llm_request.append_instructions([skill_content]) instead
  of directly modifying llm_request.system_instruction (which doesn't exist)
- README.md: Update documentation to reflect direct injection architecture
- Add comprehensive ADK Skills Framework design document

Technical details:
- The append_instructions() method properly concatenates to config.system_instruction
- This ensures skills are available in the FIRST LLM call by injecting directly
  into the llm_request in before_model_callback
- Fixes timing issue where instruction provider runs before callback

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Major revision (v2.0) positioning Skills as a core ADK plugin:

- Frame Skills as the fourth plugin primitive alongside Tools, Callbacks, Extensions
- Add "what agent KNOWS" vs "what agent can DO" distinction
- Define Skill as self-contained unit of domain knowledge

Key additions:
- ADK Plugin Ecosystem diagram showing Skills' unique role
- Skill vs Tool decision matrix with concrete examples
- Multiple domain case studies: BigQuery, Kubernetes, Compliance, Internal Standards
- Full API specification for SkillRegistry, SkillCallbacks, SkillExtension
- Integration patterns: Toolset bundling, Multi-domain, Composition, Conditional
- Detailed rollout phases (Q1-Q4 2026)
- Future roadmap: Multi-modal, Executable, Federated, Learning skills

Technical details:
- Progressive disclosure (Level 1 metadata, Level 2 content)
- Injection mechanism using llm_request.append_instructions()
- Multi-turn handling with skill state management
- Detection strategies comparison (Keyword, LLM, Hybrid)
- Performance analysis with cost projections

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Remove author, version, and target audience metadata
- Remove Q1-Q4 2026 timeline references from phase headings
- Remove document footer with version info

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
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.

3 participants