Skip to content

feat: tool calling and Agent primitive#2059

Closed
ValbuenaVC wants to merge 1 commit into
microsoft:mainfrom
ValbuenaVC:vvalbuena-microsoft-story-3-tool-calling-agent
Closed

feat: tool calling and Agent primitive#2059
ValbuenaVC wants to merge 1 commit into
microsoft:mainfrom
ValbuenaVC:vvalbuena-microsoft-story-3-tool-calling-agent

Conversation

@ValbuenaVC

Copy link
Copy Markdown
Contributor

Summary

Implements Story 3 — Tool Calling and Agent Primitive. Adds a new pyrit.agent package that gives any PromptTarget universal tool-calling capability without modifying existing targets or attacks.

Changes

New package: pyrit/agent/

tools.py (S3.1) — Core tool primitives:

  • Tool: Pydantic model with name, description, json_schema, callable fields; hashable by name so tools can live in sets.
  • ToolCall / ToolResult: Type aliases mirroring the function_call shape from OpenAIResponseTarget.
  • ToolCallDispatch: Protocol satisfied by any dispatcher backend (structural subtyping).

runtime.py (S3.2) — InProcessRuntime implementing ToolCallDispatch:

  • Executes registered Python callables in-process.
  • Returns structured error dicts for unknown tools, malformed args, and runtime exceptions — mirroring OpenAIResponseTarget._execute_call_section_async.

agent.py (S3.4) — Agent(PromptTarget):

  • Wraps any PromptTarget and executes the tool-call/result loop.
  • Calls the inner target's _send_prompt_to_target_async directly to keep interim tool turns in-context without memory duplication (same pattern as OpenAIResponseTarget).
  • max_tool_iterations guard (default 10) prevents infinite loops.
  • Because Agent IS-A PromptTarget, attacks and scenarios accept it with no changes.

Modified: pyrit/models/target_capabilities.py (S3.3)

  • ToolUsageSchema: New frozen Pydantic model specifying which data types signal tool calls/results.
  • CapabilityName.TOOL_USAGE = "supports_tool_usage": Points at the bool field so includes() works correctly.
  • TargetCapabilities: Two new fields — supports_tool_usage: bool = False and tool_usage_schema: ToolUsageSchema | None = None. Defaults keep all existing targets unchanged.

Modified: pyrit/prompt_target/common/discover_target_capabilities.py

  • Added supports_tool_usage=True to _permissive_configuration so it declares every boolean capability as supported.

Tests

File Subfeature Tests
tests/unit/agent/test_tools.py S3.1 12
tests/unit/agent/test_runtime.py S3.2 8
tests/unit/models/test_target_capabilities_tool_usage.py S3.3 17
tests/unit/agent/test_agent.py S3.4 7
tests/unit/agent/test_attack_parity.py S3.5 6

Total: 50 new tests; 9858 total unit tests pass.

Quality gate

  • make pre-commit: all hooks pass (ruff, ty, _async suffix, etc.)
  • make ty: zero new type errors introduced (494 pre-existing)
  • Coverage on new code: 96% (gate: 78%)

- S3.1: Add Tool + ToolCallDispatch protocol (pyrit/agent/tools.py)
  Tool is a Pydantic model with name/description/json_schema/callable fields.
  ToolCallDispatch is a Protocol satisfied by any dispatcher backend.
  ToolCall/ToolResult are type aliases mirroring the function_call shape.

- S3.2: Add InProcessRuntime (pyrit/agent/runtime.py)
  Default ToolCallDispatch backend executing Python callables in-process.
  Unknown tools, exceptions, and malformed args return structured error dicts.

- S3.3: Extend TargetCapabilities with tool-usage fields
  Add supports_tool_usage: bool = False and tool_usage_schema: ToolUsageSchema | None = None.
  Add TOOL_USAGE = 'supports_tool_usage' to CapabilityName enum.
  Update _permissive_configuration to include supports_tool_usage=True.
  Export ToolUsageSchema from pyrit.models.

- S3.4: Add Agent(PromptTarget) (pyrit/agent/agent.py)
  Wraps any PromptTarget and executes tool-call/result loop.
  Calls inner target's _send_prompt_to_target_async directly to keep
  interim tool turns in-context without memory duplication.
  max_tool_iterations guard prevents infinite loops.

- S3.5: Attack interface parity tests
  Agent IS-A PromptTarget; attacks accept it with no signature changes.
  Tests verify PromptSendingAttack runs end-to-end against Agent.

- S3.6: Exports, linting, coverage
  pyrit/agent/__init__.py exports Agent, InProcessRuntime, Tool, ToolCall,
  ToolCallDispatch, ToolResult.
  All pre-commit hooks pass; coverage 96% for new code (gate: 78%).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@ValbuenaVC ValbuenaVC closed this Jun 20, 2026
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.

1 participant