Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

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 TokenCredential and AsyncTokenCredential from azure-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

  1. Before agent execution (prompt phase): all context.messages are evaluated.
  2. If blocked: context.result is replaced with a system message and context.terminate = True.
  3. After successful agent execution (response phase): the produced messages are evaluated.
  4. 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_id per request (e.g. in ChatMessage(..., 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_message and blocked_response_message in PurviewSettings. 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.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agent_framework_purview-1.0.0b251016.tar.gz (29.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agent_framework_purview-1.0.0b251016-py3-none-any.whl (20.9 kB view details)

Uploaded Python 3

File details

Details for the file agent_framework_purview-1.0.0b251016.tar.gz.

File metadata

File hashes

Hashes for agent_framework_purview-1.0.0b251016.tar.gz
Algorithm Hash digest
SHA256 6cb7ac962e42a5c75d9fd8dcca020fb8dd6321c020028e834d01adc6be2ee053
MD5 020904a0553947afdeeb74e1eeb0373d
BLAKE2b-256 4917a37aaaa69281d4453edffc3bdc2b38afc62ed2dadc8b94a339d53beb37f2

See more details on using hashes here.

File details

Details for the file agent_framework_purview-1.0.0b251016-py3-none-any.whl.

File metadata

File hashes

Hashes for agent_framework_purview-1.0.0b251016-py3-none-any.whl
Algorithm Hash digest
SHA256 fa5be4ce7738e60792668d65c67e2a8e915017248cff1a40bf5ec5d2c6860635
MD5 e2f24cd69de52cdbe56f41a497ece3f0
BLAKE2b-256 e667f8ed2d7d87c228d4d6ac0f6fd6e4cf458d82df80306cde088a37ff02cd49

See more details on using hashes here.

Release history Release notifications | RSS feed

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page