3737from ..skills import prompt
3838from .base_tool import BaseTool
3939from .base_toolset import BaseToolset
40+ from .function_tool import FunctionTool
4041from .tool_context import ToolContext
4142
4243if TYPE_CHECKING :
44+ from ..agents .llm_agent import ToolUnion
4345 from ..models .llm_request import LlmRequest
4446
4547logger = logging .getLogger ("google_adk." + __name__ )
@@ -138,6 +140,15 @@ async def run_async(
138140 "error_code" : "SKILL_NOT_FOUND" ,
139141 }
140142
143+ # Record skill activation in agent state for tool resolution.
144+ agent_name = tool_context .agent_name
145+ state_key = f"_adk_activated_skill_{ agent_name } "
146+
147+ activated_skills = list (tool_context .state .get (state_key , []))
148+ if skill_name not in activated_skills :
149+ activated_skills .append (skill_name )
150+ tool_context .state [state_key ] = activated_skills
151+
141152 return {
142153 "skill_name" : skill_name ,
143154 "instructions" : skill .instructions ,
@@ -586,6 +597,7 @@ def __init__(
586597 * ,
587598 code_executor : Optional [BaseCodeExecutor ] = None ,
588599 script_timeout : int = _DEFAULT_SCRIPT_TIMEOUT ,
600+ additional_tools : list [ToolUnion ] | None = None ,
589601 ):
590602 """Initializes the SkillToolset.
591603
@@ -609,20 +621,73 @@ def __init__(
609621 self ._code_executor = code_executor
610622 self ._script_timeout = script_timeout
611623
624+ self ._provided_tools_by_name = {}
625+ for tool_union in additional_tools or []:
626+ if isinstance (tool_union , BaseTool ):
627+ self ._provided_tools_by_name [tool_union .name ] = tool_union
628+ elif callable (tool_union ):
629+ ft = FunctionTool (tool_union )
630+ self ._provided_tools_by_name [ft .name ] = ft
631+
612632 # Initialize core skill tools
613633 self ._tools = [
614634 ListSkillsTool (self ),
615635 LoadSkillTool (self ),
616636 LoadSkillResourceTool (self ),
637+ RunSkillScriptTool (self ),
617638 ]
618- # Always add RunSkillScriptTool, relies on invocation_context fallback if _code_executor is None
619- self ._tools .append (RunSkillScriptTool (self ))
620639
621640 async def get_tools (
622641 self , readonly_context : ReadonlyContext | None = None
623642 ) -> list [BaseTool ]:
624643 """Returns the list of tools in this toolset."""
625- return self ._tools
644+ dynamic_tools = await self ._resolve_additional_tools_from_state (
645+ readonly_context
646+ )
647+ return self ._tools + dynamic_tools
648+
649+ async def _resolve_additional_tools_from_state (
650+ self , readonly_context : ReadonlyContext | None
651+ ) -> list [BaseTool ]:
652+ """Resolves tools listed in the "adk_additional_tools" metadata of skills."""
653+
654+ if not readonly_context :
655+ return []
656+
657+ agent_name = readonly_context .agent_name
658+ state_key = f"_adk_activated_skill_{ agent_name } "
659+ activated_skills = readonly_context .state .get (state_key , [])
660+
661+ if not activated_skills :
662+ return []
663+
664+ additional_tool_names = set ()
665+ for skill_name in activated_skills :
666+ skill = self ._skills .get (skill_name )
667+ if skill :
668+ additional_tools = skill .frontmatter .metadata .get (
669+ "adk_additional_tools"
670+ )
671+ if additional_tools :
672+ additional_tool_names .update (additional_tools )
673+
674+ if not additional_tool_names :
675+ return []
676+
677+ resolved_tools = []
678+ existing_tool_names = {t .name for t in self ._tools }
679+ for name in additional_tool_names :
680+ if name in self ._provided_tools_by_name :
681+ tool = self ._provided_tools_by_name [name ]
682+ if tool .name in existing_tool_names :
683+ logger .error (
684+ "Tool name collision: tool '%s' already exists." , tool .name
685+ )
686+ continue
687+ resolved_tools .append (tool )
688+ existing_tool_names .add (tool .name )
689+
690+ return resolved_tools
626691
627692 def _get_skill (self , name : str ) -> models .Skill | None :
628693 """Retrieves a skill by name."""
0 commit comments