Follow-up to #7266, with the interceptability question now settled empirically for all three Harness native capabilities. Summary up front: FileAccess and FileMemory are already fully interceptable by function-call middleware (thanks @westey-m for confirming), WebSearch is not, and the two behave oppositely with respect to the tool collection in a way worth fixing.
What I verified
Using a real IChatClient.AsHarnessAgent(...) over a scripted fake client (net10.0, Microsoft.Agents.AI 1.13.0 / Microsoft.Agents.AI.Harness 1.13.0-preview.260703.1), registering a function-invocation middleware via AIAgentBuilder.Use((agent, context, next, ct) => …):
| Capability |
Runtime shape |
In static ChatOptions.Tools? |
Seen by function middleware by name? |
FileAccess (file_access_*) |
ApprovalRequiredAIFunction (via FileAccessProvider, an AIContextProvider) |
No (injected into per-invocation AIContext.Tools) |
Yes — observed file_access_read, and not calling next() suppressed the real AgentFileStore.ReadAsync |
FileMemory (file_memory_*) |
same |
No |
Yes (same mechanism) |
WebSearch (web_search) |
HostedWebSearchTool (added directly to ChatOptions.Tools at build) |
Yes |
No — never surfaces as a local FunctionCallContent |
So the file tools are invisible in the static tool list but interceptable; WebSearch is visible in the list (as a marker, .Name == "web_search") but not interceptable. Visibility and interceptability are inverted between them.
Why WebSearch can't be intercepted
HostedWebSearchTool is, by its own doc, "a marker … [that] does not itself implement web searches". The provider executes the search server-side within one model round-trip, so there is no local function invocation for any middleware to observe or authorize. A DelegatingChatClient can see the marker on the way out and the CitationAnnotation/UriContent on the way back, but there is no pre-execution hook on the query itself.
Why this matters (risk)
- Exfiltration. The model composes the search query; it leaves to an external search engine server-side with no local pre-execution authorization point. Data encoded into a query exfiltrates without any middleware getting a say — unlike a
file_access_* or caller-registered tool call, which can be inspected and blocked pre-execution.
- Indirect prompt injection. Provider web search typically retrieves and summarizes page content, pulling attacker-controllable text into the model context. The retrieved content is not surfaced through an interceptable seam either.
For a guardrail/policy layer that inspects and authorizes tool calls pre-execution, WebSearch is the one native capability that is structurally invisible to it — and it happens to be the highest-egress-risk of the three.
Ask
Any one of these would close the gap, roughly in order of preference:
- Route the web-search invocation through the same interceptable path as FileAccess/FileMemory — i.e. surface the search as an intercept point (a local
AIFunction-like seam or an AIContextProvider-mediated call) so function-call middleware can observe/authorize the query and see the results, exactly as it can for file_access_* today.
- Failing that, expose a pluggable web-search backend analogous to
HarnessAgentOptions.FileAccessStore / FileMemoryStore (e.g. a WebSearchStore / IWebSearchProvider), so a caller can supply an implementation they control and mediate. This is the pattern that already makes the file capabilities inspectable at the store boundary.
- At minimum, a request-authorize + result-inspection callback on
HarnessAgentOptions for hosted tools (invoked with the proposed query before dispatch and the results after), plus documentation that HostedWebSearchTool is provider-executed and cannot be intercepted at the function-call seam.
Note that (1)/(2) would also generalize to other Hosted*Tool capabilities (hosted MCP, code interpreter, hosted file search), which share the same "declared but not locally interceptable" property.
Happy to share the minimal repro probe if useful.
Follow-up to #7266, with the interceptability question now settled empirically for all three Harness native capabilities. Summary up front: FileAccess and FileMemory are already fully interceptable by function-call middleware (thanks @westey-m for confirming), WebSearch is not, and the two behave oppositely with respect to the tool collection in a way worth fixing.
What I verified
Using a real
IChatClient.AsHarnessAgent(...)over a scripted fake client (net10.0,Microsoft.Agents.AI1.13.0 /Microsoft.Agents.AI.Harness1.13.0-preview.260703.1), registering a function-invocation middleware viaAIAgentBuilder.Use((agent, context, next, ct) => …):ChatOptions.Tools?file_access_*)ApprovalRequiredAIFunction(viaFileAccessProvider, anAIContextProvider)AIContext.Tools)file_access_read, and not callingnext()suppressed the realAgentFileStore.ReadAsyncfile_memory_*)web_search)HostedWebSearchTool(added directly toChatOptions.Toolsat build)FunctionCallContentSo the file tools are invisible in the static tool list but interceptable; WebSearch is visible in the list (as a marker,
.Name == "web_search") but not interceptable. Visibility and interceptability are inverted between them.Why WebSearch can't be intercepted
HostedWebSearchToolis, by its own doc, "a marker … [that] does not itself implement web searches". The provider executes the search server-side within one model round-trip, so there is no local function invocation for any middleware to observe or authorize. ADelegatingChatClientcan see the marker on the way out and theCitationAnnotation/UriContenton the way back, but there is no pre-execution hook on the query itself.Why this matters (risk)
file_access_*or caller-registered tool call, which can be inspected and blocked pre-execution.For a guardrail/policy layer that inspects and authorizes tool calls pre-execution, WebSearch is the one native capability that is structurally invisible to it — and it happens to be the highest-egress-risk of the three.
Ask
Any one of these would close the gap, roughly in order of preference:
AIFunction-like seam or anAIContextProvider-mediated call) so function-call middleware can observe/authorize the query and see the results, exactly as it can forfile_access_*today.HarnessAgentOptions.FileAccessStore/FileMemoryStore(e.g. aWebSearchStore/IWebSearchProvider), so a caller can supply an implementation they control and mediate. This is the pattern that already makes the file capabilities inspectable at the store boundary.HarnessAgentOptionsfor hosted tools (invoked with the proposed query before dispatch and the results after), plus documentation thatHostedWebSearchToolis provider-executed and cannot be intercepted at the function-call seam.Note that (1)/(2) would also generalize to other
Hosted*Toolcapabilities (hosted MCP, code interpreter, hosted file search), which share the same "declared but not locally interceptable" property.Happy to share the minimal repro probe if useful.