Add M7.6 provider tool access control and M7.7 agent delegation for ToolStep
This commit is contained in:
+54
-4
@@ -5,7 +5,7 @@ import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from typing import Optional, List
|
||||
|
||||
import yaml
|
||||
|
||||
@@ -781,6 +781,23 @@ def execute_tool_step(
|
||||
# Determine effective provider (step override > parent override)
|
||||
effective_provider = step.provider or provider_override
|
||||
|
||||
# Check tool access if the provider restricts which tools it can call
|
||||
if effective_provider:
|
||||
from .providers import get_provider
|
||||
provider_obj = get_provider(effective_provider)
|
||||
if provider_obj and provider_obj.tools is not None:
|
||||
allowed = provider_obj.tools
|
||||
if step.tool not in allowed and not _tool_match_allowlist(step.tool, allowed):
|
||||
_print_call_stack(
|
||||
call_stack,
|
||||
f"Provider '{effective_provider}' is not allowed to call tool '{step.tool}'",
|
||||
)
|
||||
print(
|
||||
f"Provider '{effective_provider}' tools allowlist: {allowed}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return "", False
|
||||
|
||||
if verbose:
|
||||
print(f"[verbose] Tool step: calling {step.tool}", file=sys.stderr)
|
||||
print(f"[verbose] Input length: {len(input_text)} chars", file=sys.stderr)
|
||||
@@ -799,7 +816,9 @@ def execute_tool_step(
|
||||
show_prompt=False,
|
||||
verbose=verbose,
|
||||
_depth=depth + 1,
|
||||
_call_stack=call_stack
|
||||
_call_stack=call_stack,
|
||||
agent_profile=step.profile,
|
||||
agent_skills=step.skills,
|
||||
)
|
||||
|
||||
return output, exit_code == 0
|
||||
@@ -815,7 +834,9 @@ def run_tool(
|
||||
verbose: bool = False,
|
||||
auto_install: bool = False,
|
||||
_depth: int = 0,
|
||||
_call_stack: Optional[list] = None
|
||||
_call_stack: Optional[list] = None,
|
||||
agent_profile: Optional[str] = None,
|
||||
agent_skills: Optional[List[str]] = None,
|
||||
) -> tuple[str, int]:
|
||||
"""
|
||||
Execute a tool.
|
||||
@@ -940,8 +961,14 @@ def run_tool(
|
||||
if dry_run:
|
||||
variables[step.output_var] = f"[DRY RUN - would call {step.provider}]"
|
||||
else:
|
||||
# Apply agent-level defaults if step doesn't set its own
|
||||
effective_step = step
|
||||
if agent_profile and not step.profile:
|
||||
effective_step = _step_with_profile(step, agent_profile)
|
||||
if agent_skills is not None and step.skills is None:
|
||||
effective_step = _step_with_skills(effective_step, agent_skills)
|
||||
output, success = execute_prompt_step(
|
||||
step,
|
||||
effective_step,
|
||||
variables,
|
||||
provider_override,
|
||||
verbose=verbose,
|
||||
@@ -1200,5 +1227,28 @@ def main():
|
||||
sys.exit(exit_code)
|
||||
|
||||
|
||||
def _tool_match_allowlist(name: str, allowed: list) -> bool:
|
||||
for pattern in allowed:
|
||||
if pattern == name:
|
||||
return True
|
||||
if pattern.endswith("*") and name.startswith(pattern[:-1]):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _step_with_profile(step, profile_name):
|
||||
from copy import copy
|
||||
s = copy(step)
|
||||
s.profile = profile_name
|
||||
return s
|
||||
|
||||
|
||||
def _step_with_skills(step, skill_names):
|
||||
from copy import copy
|
||||
s = copy(step)
|
||||
s.skills = skill_names
|
||||
return s
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user