Skip to content

Python: Add tool name prefixes to FileAccessProvider - #9654

Open
Jose Alvarez (jpalvarezl) wants to merge 1 commit into
mainfrom
jpalvarezl/fix/issue_9646_tool_dups_multiple_file_stores
Open

Jose Alvarez (jpalvarezl) wants to merge 1 commit into
mainfrom
jpalvarezl/fix/issue_9646_tool_dups_multiple_file_stores

Conversation

@jpalvarezl

Copy link
Copy Markdown
Member

Motivation & Context

An agent configured with multiple FileAccessProvider instances fails while merging tools because every provider exposes the same file_access_* names, even when the providers have distinct source IDs and independently rooted stores.

Allow callers to distinguish each provider's tools so an agent can access multiple file stores without tool-name collisions.

Description & Review Guide

  • What are the major changes?
    • Add an optional, keyword-only tool_name_prefix constructor parameter to FileAccessProvider and apply it to all eight registered tool names.
    • Keep the existing names when the prefix is omitted or empty. A prefix such as spec produces names such as spec_file_access_read.
    • Add regression coverage for the issue reproduction, distinct prefixes, prefixed/default provider coexistence, all eight tool names, and reads/writes routed to the correct store.
  • What is the impact of these changes?
    • Providers with distinct tool names can coexist on one agent without changing the default tool names or shared class constants.
    • Distinct source IDs alone still do not prevent collisions; callers must configure distinct prefixes when combining providers.
  • What do you want reviewers to focus on?
    • Prefix semantics, backward compatibility, and correct per-store routing.
    • This is a draft: default instructions and the static auto-approval rules still refer to the original, unprefixed names. Those surfaces need to be aligned with prefixed names before the change is ready for review. The auto-approval mismatch fails closed and leaves approval required.

Related Issue

Fixes #9646

Maintainer agreement with the direction was explicitly confirmed by the submitter during preparation of this draft. No competing open PR was found for the issue.

AI Assistance

  • No material AI assistance was used.
  • This is an AI-assisted contribution. I reviewed, understood, and verified all submitted content and accept responsibility for it.

AI assistance details: GitHub Copilot assisted with code analysis and review, regression tests, validation, and this PR description. The implementation was authored by the contributor.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR links to an agreed issue with no competing open PR, or the Related Issue section documents a trivial-change or repository-automation exception.
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

The focused file-access unit test module passes: 131 passed, 7 skipped, with three existing warnings. Ruff lint/format checks and Pyright pass for both changed files. The full core unit suite and a package build have not been run, so their checklist items remain unchecked.

@github-code-quality

Copy link
Copy Markdown
Contributor

Code coverage overview

Languages: Python

Python / code-coverage/python

main edc2427 jpalvarezl/fix/issue... 5e1d6a7 +/-
92% 92% 0%

ℹ️ Calculations represent line coverage. Results may change as calculations are updated.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Model-facing guidance and auto-approval rules still use unprefixed names and need to support the configured prefixes.

2 open issues
What changed in this PR

Adds optional tool-name prefixes to Python’s FileAccessProvider, addressing #9646 by allowing independently rooted stores to coexist on one agent without tool-name collisions.

Changes:

  • Adds keyword-only tool_name_prefix and applies it to all eight tools.
  • Preserves existing tool names when the prefix is omitted or empty.
  • Adds regression coverage for collisions, mixed provider configurations, and per-store read/write routing.
File Description
python/​packages/​core/​tests/​core/​test_harness_file_access.py Tests prefix naming, provider coexistence, and isolated store routing.
python/​packages/​core/​agent_framework/​_harness/​_file_access.py Adds prefix configuration and applies it during tool registration.

Review effort: Balanced

self.disable_write_tool_approval = disable_write_tool_approval
self.session_scoped = session_scoped
self.scope = scope
self.tool_name_prefix = tool_name_prefix
Comment on lines +2052 to +2053
def _prefixed_tool_name(self, name: str) -> str:
return f"{self.tool_name_prefix}_{name}" if self.tool_name_prefix else name

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

MAF Automated Review — Iteration 1

Result: Findings reported
Scope: full PR (1 commit(s)): 5e1d6a75ec8b
Model: gpt-5.6-sol

Overview

The PR consistently applies the configured prefix to all eight tools, preserves default names for falsey prefixes, rejects remaining duplicate names centrally, and tests per-store routing. However, renaming leaves the public auto-approval rules authoritative over the old names, which can bypass approval for an unrelated local tool, while the default model instructions still advertise those old names. Prefixes are also accepted verbatim even when they produce names rejected by model providers.

Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
3 verified findings remained after source verification (1 high, 2 medium) across 1 file. Details are attached to the affected lines below.

Affected areas: python/packages/core/agent_framework/_harness/_file_access.py

)

def _prefixed_tool_name(self, name: str) -> str:
return f"{self.tool_name_prefix}_{name}" if self.tool_name_prefix else name

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

After a provider is prefixed, this frees the canonical file_access_* names while the public static auto-approval rules still approve those names. An approval-required local tool registered as file_access_write can now coexist and will be auto-approved, bypassing the human gate; meanwhile the real prefixed file tool is not matched. Make the approval rules provider/prefix-bound and match only that provider's effective names, so renaming also removes authority from the old names.


@tool(name=FileAccessProvider.WRITE_TOOL_NAME, schema=_WriteFileInput, approval_mode=write_approval)
@tool(
name=self._prefixed_tool_name(FileAccessProvider.WRITE_TOOL_NAME),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

When a prefix is set, this renames the registered tools but instructions remains DEFAULT_FILE_ACCESS_INSTRUCTIONS, which tells the model to call unprefixed file_access_* names. In the supported prefixed-plus-default setup, those directions select the default provider, so requests intended for the prefixed store can read or modify the wrong store; with only prefixed providers they name nonexistent tools. Render the injected instructions and cross-tool references from each provider's effective names.

self.disable_write_tool_approval = disable_write_tool_approval
self.session_scoped = session_scoped
self.scope = scope
self.tool_name_prefix = tool_name_prefix

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

tool_name_prefix is stored verbatim, so whitespace, /, Unicode, or a long prefix can produce function names that violate provider identifier or 64-character limits. Core accepts these names and adapters forward them, causing a remote request failure instead of a usable provider. Validate or normalize the prefix, including the final generated-name length, when constructing the provider.

This branch was successfully deployed

1 active deployment
github-app-auth — 5e1d6a75 Deployed Oct 23, 2026 by jpalvarezl via team_check #7347
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: Multiple FileAccessProvider context providers fail with duplicate tool names

2 participants