Microsoft Purview (Graph dataSecurityAndGovernance) integration for Microsoft Agent Framework.
Project description
Microsoft Agent Framework – Purview Integration (Python)
agent-framework-purview adds Microsoft Purview (Microsoft Graph dataSecurityAndGovernance) policy evaluation to the Microsoft Agent Framework. It lets you enforce data security / governance policies on both the prompt (user input + conversation history) and the model response before they proceed further in your workflow.
Status: Preview
Key Features
- Middleware-based policy enforcement (agent-level and chat-client level)
- Blocks or allows content at both ingress (prompt) and egress (response)
- Works with any
ChatAgent/ agent orchestration using the standard Agent Framework middleware pipeline - Supports both synchronous
TokenCredentialandAsyncTokenCredentialfromazure-identity - Simple, typed configuration via
PurviewSettings/PurviewAppLocation - Two middleware types:
PurviewPolicyMiddleware(Agent pipeline)PurviewChatPolicyMiddleware(Chat client middleware list)
When to Use
Add Purview when you need to:
- Prevent sensitive or disallowed content from being sent to an LLM
- Prevent model output containing disallowed data from leaving the system
- Apply centrally managed policies without rewriting agent logic
Quick Start
import asyncio
from agent_framework import ChatAgent, ChatMessage, Role
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.microsoft import PurviewPolicyMiddleware, PurviewSettings
from azure.identity import InteractiveBrowserCredential
async def main():
chat_client = AzureOpenAIChatClient() # uses environment for endpoint + deployment
purview_middleware = PurviewPolicyMiddleware(
credential=InteractiveBrowserCredential(),
settings=PurviewSettings(app_name="My Sample App")
)
agent = ChatAgent(
chat_client=chat_client,
instructions="You are a helpful assistant.",
middleware=[purview_middleware]
)
response = await agent.run(ChatMessage(role=Role.USER, text="Summarize zero trust in one sentence."))
print(response)
asyncio.run(main())
If a policy violation is detected on the prompt, the middleware terminates the run and substitutes a system message: "Prompt blocked by policy". If on the response, the result becomes "Response blocked by policy".
Authentication
PurviewClient uses the azure-identity library for token acquisition. You can use any TokenCredential or AsyncTokenCredential implementation.
The APIs require the following Graph Permissions:
- ProtectionScopes.Compute.All : (userProtectionScopeContainer)[https://learn.microsoft.com/en-us/graph/api/userprotectionscopecontainer-compute]
- Content.Process.All : (processContent)[https://learn.microsoft.com/en-us/graph/api/userdatasecurityandgovernance-processcontent]
- ContentActivity.Write : (contentActivity)[https://learn.microsoft.com/en-us/graph/api/activitiescontainer-post-contentactivities]
Scopes
PurviewSettings.get_scopes() derives the Graph scope list (currently https://graph.microsoft.com/.default style).
Tenant Enablement for Purview
- The tenant requires an e5 license and consumptive billing setup.
- There need to be (Data Loss Prevention)[https://learn.microsoft.com/en-us/purview/dlp-create-deploy-policy] or (Data Collection Policies)[https://learn.microsoft.com/en-us/purview/collection-policies-policy-reference] that apply to the user to call Process Content API else it calls Content Activities API for auditing the message.
Configuration
PurviewSettings
PurviewSettings(
app_name="My App", # Display / logical name
tenant_id=None, # Optional – used mainly for auth context
purview_app_location=None, # Optional PurviewAppLocation for scoping
graph_base_uri="https://graph.microsoft.com/v1.0/",
process_inline=False, # Reserved for future inline processing optimizations
blocked_prompt_message="Prompt blocked by policy", # Custom message for blocked prompts
blocked_response_message="Response blocked by policy" # Custom message for blocked responses
)
To scope evaluation by location (application, URL, or domain):
from agent_framework.microsoft import (
PurviewAppLocation,
PurviewLocationType,
PurviewSettings,
)
settings = PurviewSettings(
app_name="Contoso Support",
purview_app_location=PurviewAppLocation(
location_type=PurviewLocationType.APPLICATION,
location_value="<app-client-id>"
)
)
Customizing Blocked Messages
By default, when Purview blocks a prompt or response, the middleware returns a generic system message. You can customize these messages by providing your own text in the PurviewSettings:
from agent_framework.microsoft import PurviewSettings
settings = PurviewSettings(
app_name="My App",
blocked_prompt_message="Your request contains content that violates our policies. Please rephrase and try again.",
blocked_response_message="The response was blocked due to policy restrictions. Please contact support if you need assistance."
)
This is useful for:
- Providing more user-friendly error messages
- Including support contact information
- Localizing messages for different languages
- Adding branding or specific guidance for your application
Selecting Agent vs Chat Middleware
Use the agent middleware when you already have / want the full agent pipeline:
from agent_framework import ChatAgent
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.microsoft import PurviewPolicyMiddleware, PurviewSettings
from azure.identity import DefaultAzureCredential
credential = DefaultAzureCredential()
client = AzureOpenAIChatClient()
agent = ChatAgent(
chat_client=client,
instructions="You are helpful.",
middleware=[PurviewPolicyMiddleware(credential, PurviewSettings(app_name="My App"))]
)
Use the chat middleware when you attach directly to a chat client (e.g. minimal agent shell or custom orchestration):
import os
from agent_framework import ChatAgent
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.microsoft import PurviewChatPolicyMiddleware, PurviewSettings
from azure.identity import DefaultAzureCredential
credential = DefaultAzureCredential()
chat_client = AzureOpenAIChatClient(
deployment_name=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"],
endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
credential=credential,
middleware=[
PurviewChatPolicyMiddleware(credential, PurviewSettings(app_name="My App (Chat)"))
],
)
agent = ChatAgent(chat_client=chat_client, instructions="You are helpful.")
The policy logic is identical; the difference is only the hook point in the pipeline.
Middleware Lifecycle
- Before agent execution (
prompt phase): allcontext.messagesare evaluated. - If blocked:
context.resultis replaced with a system message andcontext.terminate = True. - After successful agent execution (
response phase): the produced messages are evaluated. - If blocked: result messages are replaced with a blocking notice.
When a user identifier is discovered (e.g. in ChatMessage.additional_properties['user_id']) during the prompt phase it is reused for the response phase so both evaluations map consistently to the same user.
You can customize the blocking messages using the blocked_prompt_message and blocked_response_message fields in PurviewSettings. For more advanced scenarios, you can wrap the middleware or post-process context.result in later middleware.
Exceptions
| Exception | Scenario |
|---|---|
PurviewAuthenticationError |
Token acquisition / validation issues |
PurviewRateLimitError |
429 responses from service |
PurviewRequestError |
4xx client errors (bad input, unauthorized, forbidden) |
PurviewServiceError |
5xx or unexpected service errors |
Catch broadly if you want unified fallback:
from agent_framework.microsoft import (
PurviewAuthenticationError, PurviewRateLimitError,
PurviewRequestError, PurviewServiceError
)
try:
...
except (PurviewAuthenticationError, PurviewRateLimitError, PurviewRequestError, PurviewServiceError) as ex:
# Log / degrade gracefully
print(f"Purview enforcement skipped: {ex}")
Notes
- Provide a
user_idper request (e.g. inChatMessage(..., additional_properties={"user_id": "<guid>"})) when possible for per-user policy scoping; otherwise supply a default via settings or environment. - Blocking messages can be customized via
blocked_prompt_messageandblocked_response_messageinPurviewSettings. By default, they are "Prompt blocked by policy" and "Response blocked by policy" respectively. - Streaming responses: post-response policy evaluation presently applies only to non-streaming chat responses.
- Errors during policy checks are logged and do not fail the run; they degrade gracefully.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agent_framework_purview-1.0.0b251016.tar.gz.
File metadata
- Download URL: agent_framework_purview-1.0.0b251016.tar.gz
- Upload date:
- Size: 29.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.23
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6cb7ac962e42a5c75d9fd8dcca020fb8dd6321c020028e834d01adc6be2ee053
|
|
| MD5 |
020904a0553947afdeeb74e1eeb0373d
|
|
| BLAKE2b-256 |
4917a37aaaa69281d4453edffc3bdc2b38afc62ed2dadc8b94a339d53beb37f2
|
File details
Details for the file agent_framework_purview-1.0.0b251016-py3-none-any.whl.
File metadata
- Download URL: agent_framework_purview-1.0.0b251016-py3-none-any.whl
- Upload date:
- Size: 20.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.23
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa5be4ce7738e60792668d65c67e2a8e915017248cff1a40bf5ec5d2c6860635
|
|
| MD5 |
e2f24cd69de52cdbe56f41a497ece3f0
|
|
| BLAKE2b-256 |
e667f8ed2d7d87c228d4d6ac0f6fd6e4cf458d82df80306cde088a37ff02cd49
|