Repository navigation
Python: Fix M365 agent sample startup and anonymous mode - #9598
Naveen Chatlapalli (1aifanatic) wants to merge 3 commits into
Conversation
- aiohttp's Application takes middlewares=, not middleware= (TypeError at startup). - FoundryChatClient needs a credential; pass AzureCliCredential and document the FOUNDRY_* settings the sample actually reads instead of OpenAI ones. - The M365 Agents SDK now requires a connection manager for CloudAdapter and AgentApplication; give anonymous mode an empty service connection. - ClaimsIdentity's signature is now (claims, authentication_type, ...); build a claim-less anonymous identity so the adapter skips token acquisition. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
🔵 Needs a closer look
The anonymous identity and empty MSAL connection depend on external SDK behavior that still needs independent verification before approval.
No open issues 🎉
What changed in this PR
This PR fixes startup and anonymous messaging failures in the Python M365 agent sample reported in #9595.
Changes:
- Corrects aiohttp middleware registration and supplies an Azure CLI credential to
FoundryChatClient. - Adds a placeholder connection manager and claim-less identity for anonymous mode while preserving the authenticated configuration path.
- Updates Foundry setup instructions and corrects the run-command and configuration comments.
| File | Description |
|---|---|
python/samples/05-end-to-end/m365-agent/README.md |
Replaces OpenAI settings with Foundry configuration and Azure CLI prerequisites. |
python/samples/05-end-to-end/m365-agent/m365_agent_demo/app.py |
Fixes startup, configures anonymous SDK components, and corrects usage comments. |
Review effort: Balanced
The anonymous-mode identity uses ClaimsIdentity(authentication_type=...), which arrived in microsoft-agents-hosting-core 1.4.0; on 1.0-1.3 the constructor requires claims and is_authenticated. Verified the sample's anonymous message flow on 1.4.0 through 1.10.0.dev1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Following up on the "needs a closer look" note about relying on M365 Agents SDK behavior, I verified the two anonymous-mode pieces against the SDK source and across releases. Why the anonymous path never touches the placeholder connection (
Version matrix: the sample's anonymous flow, run end to end with aiohttp's test client (agent stubbed, local channel endpoint capturing the reply):
Because the claim-less Authenticated mode, with |
Eduard van Valkenburg (eavanvalkenburg)
left a comment
There was a problem hiding this comment.
Naveen Chatlapalli (@1aifanatic) Two material sample issues remain on this head:
- In
python/samples/05-end-to-end/m365-agent/m365_agent_demo/app.py:197-198, settingUSE_ANONYMOUS_MODE=falsedoes not install any JWT validation middleware. Missing and invalid bearer tokens still reach the agent and receive HTTP 202 responses. Please apply the SDK’s authenticated-request validation path when anonymous mode is disabled, preserve the explicit anonymous path, and add tests proving missing/invalid tokens are rejected before agent invocation. - In
python/samples/05-end-to-end/m365-agent/README.md:33-43, the documenteduv syncplus plainpython m365_agent_demo/app.pyflow does not install the script’s PEP 723 dependencies. Please document the executable PEP 723 path, such asuv run samples/05-end-to-end/m365-agent/m365_agent_demo/app.py, so a clean checkout installs the required M365 hosting/authentication packages.
Please address both before merge.
With USE_ANONYMOUS_MODE=false the sample installed no JWT validation, so requests with a missing or invalid token still reached the agent. Wrap /api/messages with the SDK's jwt_authorization_decorator and its default connection configuration, keep the anonymous middleware for anonymous mode, and document running the PEP 723 script with uv run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Eduard van Valkenburg (@eavanvalkenburg) Thanks. 3a4cf64 addresses both points. 1. Token validation when anonymous mode is off.
Anonymous mode keeps its explicit middleware, which is now installed only when New tests in
Anonymous mode returns 202 with an All 8 tests pass with 2. README. It now runs the script with |
Motivation & Context
The M365 Agents SDK sample (
python/samples/05-end-to-end/m365-agent) does not start, and once startup is fixed, anonymous mode still cannot answer a message. Details and reproduction in #9595:web.Application(middleware=...)raisesTypeError, because aiohttp's keyword ismiddlewares. Themiddlewares→middlewarerename (Python: [BREAKING]: removed display_name, renamed context_providers, middleware and AggregateContextProvider #3139) appears to have caught it.FoundryChatClient()is created without a credential, and the README still documents OpenAI variables.CloudAdapterandAgentApplication.ClaimsIdentitynow takes(claims, authentication_type, ...), so the sample's "anonymous" identity was treated as authenticated and the adapter tried to get an MSAL token (TENANT_ID is not set).Description & Review Guide
web.Application(middlewares=[middleware_fn]).FoundryChatClient(credential=AzureCliCredential()). The README now listsFOUNDRY_PROJECT_ENDPOINT/FOUNDRY_MODELandaz login, and the docstring no longer points to a nonexistent.env.example.build_connection_managerreturns anMsalConnectionManagerwith an emptySERVICE_CONNECTION, andbuild_authorizationalways buildsAuthorization. Anonymous requests never request tokens, so the placeholder connection is never used.ClaimsIdentity(authentication_type="Anonymous")with no claims, whichClaimsIdentity.allow_anonymousrecognizes.samples/05-end-to-end/...instead ofsamples/demos/....MsalConnectionManager(**agents_sdk_config)plusAuthorization.SERVICE_CONNECTIONis an acceptable way to satisfy the SDK in anonymous mode, or whether you would rather the sample require connection settings even for local runs.Verified with aiohttp's test client:
create_app(load_app_config())in anonymous mode, with the agent replaced by an echo stub and a local endpoint standing in for the channel service:mainTypeErroratweb.Application(middleware=...)GET /api/health200,GET /api/messages200,POST /api/messages202, and the reply activity reaches the channelI also checked that the real
build_agent()constructs with onlyFOUNDRY_*set. I could not test authenticated mode, which needs an Azure Bot registration.ruff format --checkpasses.ruff checkreports one pre-existingE501(the longapproval_modeNOTE comment), which is also onmain. Pyright's two remaining errors are pre-existing typing nits (anOptionalreturn type and the synclambdaroute handler), and both routes respond correctly at runtime.Related Issue
Fixes #9595
AI Assistance
AI assistance details: Claude Code helped trace the breakages through aiohttp and the M365 Agents SDK, implement the fix, build the test-client verification, and draft this description and the linked issue.
Contribution Checklist
breaking changelabel (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.🤖 Generated with Claude Code