Repository navigation
[BREAKING] Scope provider-backed MCP sessions per invocation - #4
Closed
jpalvarezl wants to merge 108 commits into
Closed
jpalvarezl wants to merge 108 commits into
jpalvarezl wants to merge 108 commits into
Conversation
…8213) * Build(deps): bump astral-sh/setup-uv from 9.0.0 to 10.0.1 Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 9.0.0 to 10.0.1. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](astral-sh/setup-uv@v9.0.0...20cfd1b) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 10.0.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * Change cache setting to auto in devflow PR review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Change cache enable option to auto in workflow Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
… the run's kwargs (microsoft#8225) * Added failing test * seeding run header value for auth to mcp connect * WIP: added connection_kwargs and tests * Python: fix(core): seed run kwargs into MCP connection-header resolution Constructor-supplied MCP tools now seed the run's function_invocation_kwargs before connecting, matching the run-supplied path. Adds coverage for the connect-time credential matrix and fixes the API-key sample to close over a construction-time credential. * Python: fix(core): fail the MCP handshake when seeded kwargs miss the provider's key Ambient header resolution previously swallowed every KeyError from header_provider, so a run whose kwargs did not carry the key the provider reads would silently send the initialize handshake unauthenticated and surface as a 401. Only tolerate the KeyError when no connection kwargs were seeded at all, which is the case a caller cannot avoid; a key missing from seeded kwargs is a misconfiguration and now propagates. * Python: fix(core): distinguish unseeded MCP connections and release kwargs on failed connect Addresses review on microsoft#8225. An empty mapping could not express the difference between a run that seeded no kwargs and a connection no run ever seeded, so a lazy run with empty kwargs still swallowed the provider's KeyError and sent an unauthenticated handshake. _connection_kwargs is now None until a run seeds it. The seeded kwargs were also only released through close(); a rejected handshake unwinds via _close_and_check_cancelled instead, leaving the failed run's credential for a later unseeded reconnect, so the release now happens there. Documents the connection-lifetime semantics on the public header_provider parameter. * Python: fix(core): make the MCP connection kwargs seed a first-writer claim Addresses review on microsoft#8225. is_connected only turns true after initialize returns, so two concurrent runs could both pass the guard and the second would swap the credential out from under the first run's in-flight handshake, authenticating a shared tool as the wrong caller. The seed is now a first-writer claim, released when the connection closes or its setup fails. * Update python/samples/02-agents/mcp/mcp_api_key_auth.py Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com> --------- Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Harden LocalCodeAct OS validation Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Address LocalCodeAct review feedback Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* chore: upgrades xunit dependencies chore: upgrades bcl dependencies chore: upgrades additional system dependencies chore: upgrades dotnetenv chore: upgrades mcp dependencies chore: upgrades microsoft agents object model dependencies Signed-off-by: Vincent Biret <vibiret@microsoft.com> * ci: updates to the new switch * fix: adds missing method implementations * Add InvokeMcpToolAction unsupported-action test Co-authored-by: baywet <7905502+baywet@users.noreply.github.com> * Update xUnit JUnit artifact upload pattern Retain the existing .junit glob and include xUnit 4's .junit.xml output so non-PR integration test reports are uploaded for trend aggregation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * tests: Add VoiceAuthenticate.Builder to test cases Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * tests: disables parallelization for integration tests to avoid swamping the service --------- Signed-off-by: Vincent Biret <vibiret@microsoft.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: baywet <7905502+baywet@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* ci: removes promote script and replaces by dedicated action Signed-off-by: Vincent Biret <vibiret@microsoft.com> * ci: fixes the path Signed-off-by: Vincent Biret <vibiret@microsoft.com> * ci: upgrades task to version that pins dependencies Signed-off-by: Vincent Biret <vibiret@microsoft.com> * ci: upgrades to latest action version Signed-off-by: Vincent Biret <vibiret@microsoft.com> --------- Signed-off-by: Vincent Biret <vibiret@microsoft.com>
…ions (microsoft#8206) * Python: reset $LASTEXITCODE per command in persistent PowerShell sessions $LASTEXITCODE is a session-wide automatic variable that only native (external) processes update, so in a long-lived session it stays set after such a command. Every later cmdlet-only command then took the $LASTEXITCODE branch in the sentinel script and reported that stale value instead of 0. Clear it in the global scope before invoking the user command so a non-null value can only have come from this command. The global scope qualifier matters: assigning the unqualified name inside the script block shadows the global the engine writes to, which would hide real native exit codes. * Python: snapshot $LASTEXITCODE instead of clearing it Review feedback: clearing $global:LASTEXITCODE before the user's command destroys state persistent mode exists to carry. After `cmd /c exit 3`, a following `Write-Output $LASTEXITCODE` printed nothing instead of 3. Snapshot the value before the command and compare afterwards instead. The variable is never assigned, so the user's own commands still read it, and a value that differs can only have been written by this command. $? is read on the statement right after Invoke-Expression, since anything else clobbers it. The regression test now also asserts the readback prints 3 while its own exit code is 0, which fails against the previous approach.
* fix: do not forward headers on redirect Signed-off-by: Vincent Biret <vibiret@microsoft.com> * tests: use mocked handlers instead of simulated endpoints for reliability Signed-off-by: Vincent Biret <vibiret@microsoft.com> * docs: Clarify redirect handling in DefaultHttpRequestHandler Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * chore: Improve exception handling for invalid request URI Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * docs: fixes xml doc structure Signed-off-by: Vincent Biret <vibiret@microsoft.com> * tests: linting Signed-off-by: Vincent Biret <vibiret@microsoft.com> * perf: only read headers for redirect responses Signed-off-by: Vincent Biret <vibiret@microsoft.com> * fix: aggregate timeout across redirects Signed-off-by: Vincent Biret <vibiret@microsoft.com> * fix: prevent https to http redirects Signed-off-by: Vincent Biret <vibiret@microsoft.com> * fix: do not reject provider clients on initial request Signed-off-by: Vincent Biret <vibiret@microsoft.com> * tests: refactor to avoid missing disposals Signed-off-by: Vincent Biret <vibiret@microsoft.com> * fix: do not rely on specific headers names Signed-off-by: Vincent Biret <vibiret@microsoft.com> * fix: address redirect review feedback Co-authored-by: baywet <7905502+baywet@users.noreply.github.com> * tests: ensure responses are disposed Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> * chore: suppression of linting rule Signed-off-by: Vincent Biret <vibiret@microsoft.com> * fix: reject redirect with body to different origin Signed-off-by: Vincent Biret <vibiret@microsoft.com> * fix: timeout in dotnet fx as well Signed-off-by: Vincent Biret <vibiret@microsoft.com> * fix: return the redirect response instead of throwing Signed-off-by: Vincent Biret <vibiret@microsoft.com> * Apply batched suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding 'Missing Dispose call on local IDisposable' Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> * chore: linting Signed-off-by: Vincent Biret <vibiret@microsoft.com> --------- Signed-off-by: Vincent Biret <vibiret@microsoft.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: baywet <7905502+baywet@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
* chore: updates open telemetry dependencies chore: updates trimmer dependency chore: updates copilot sdk dependency Signed-off-by: Vincent Biret <vibiret@microsoft.com> * ci: adds an open telemetry group Signed-off-by: Vincent Biret <vibiret@microsoft.com> * Update explicit OpenTelemetry sample pins Co-authored-by: baywet <7905502+baywet@users.noreply.github.com> --------- Signed-off-by: Vincent Biret <vibiret@microsoft.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>
…l sessions (microsoft#8259) * Dotnet: reset $LASTEXITCODE per command in persistent PowerShell sessions * .NET: reset LASTEXITCODE before each PowerShell command Clear the persistent automatic variable before invoking each command so repeated native failures with the same exit code are reported correctly. Update the Windows regression test to cover repeated failures and reset readback semantics. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…lt (microsoft#8283) * docs(python): clarify context.result shape contract FunctionInvocationContext.result documents one contract but carries two: middleware observe FunctionTool.invoke's parsed output and may write back a value of any type, so a type check written from the docs silently never fires. The shared-state sample modeled the wrong side and sent a Python repr of the Content list to the model instead of the tool's text. * docs(python): note the approval-request passthrough A bare Content of type function_approval_request is returned unchanged by the invocation layer on both the normal and termination paths, so the override rule as written misdirects middleware that drive approval flows.
…8269) Co-authored-by: WhaleTech <304937387+ryo-whaletech@users.noreply.github.com> Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
…) (microsoft#8162) * Python: Update Monty bridge for pydantic-monty pool API (microsoft#8152) * Python: Refresh uv.lock for pydantic-monty>=0.0.23 (microsoft#8152) * Python: drop obsolete pydantic-monty version migration comment (microsoft#8152) Floor is already >=0.0.23; no need to document the old API transition. * Python: add uv.lock platform markers for monty deps (microsoft#8152) * Revert "Python: add uv.lock platform markers for monty deps (microsoft#8152)" This reverts commit 14a48a2. * Python: refresh uv.lock for pydantic-monty 0.0.23 (microsoft#8152) Keep main's prerelease-mode and platform-marker lock format so CI uv-lock stays clean while resolving pydantic-monty>=0.0.23. --------- Co-authored-by: minelhi <3417378192@qq.com> Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
* Python: count async tool invocation exceptions * Python: track direct async tool failures
* .NET: Add Foundry hosted session client samples * .NET: Handle closed input in hosted clients * .NET: Clarify user isolation sample trust boundary * .NET: Keep preview flag on direct Toolbox MCP calls
* chore: upgrades MSAI extensions packages chore: upgrade OpenAI package Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: upgrades azure blobs chore: upgrades AGUI chore: upgrades hyperlight Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: upgrades cosmos chore: upgrades copilot studio chore: upgrades microsoft agents Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update Aspire.Azure.AI.Inference and Azure.AI.AgentServer.Core versions Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update DotNetEnv package version to 3.2.0 across multiple projects Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update Anthropic package version to 12.45.0 Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update Azure.AI.Projects package version to 3.0.0-beta.2 across multiple projects Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update AgentFrameworkVersion to 1.20.0-preview.260831.1 across multiple projects Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update ModelContextProtocol package version to 2.2.0 across multiple projects Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update ResponsibleAI.AgentHooks package version to 0.1.0-alpha.5 Signed-off-by: Vincent Biret <vibiret@microsoft.com> * fix: updated sample mapping to the wrong property Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update Microsoft.Extensions.AI.OpenAI to version 10.10.0 and OpenAI to version 2.13.0 in multiple projects Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update OllamaSharp package version to 5.4.30 Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: remove central package transitive pinning and version overrides for Microsoft.Extensions packages Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update AGUIJsonSerializerOptions usage in session persistence tests Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update AGUIJsonSerializerOptions usage in FakeTestAgentHost and SessionPersistenceTests Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update CommunityToolkit.Aspire.OllamaSharp package version to 13.5.0 Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update Microsoft.Identity.Client.Extensions.Msal package version to 4.88.0 Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: Update Microsoft.Agents.AI.Mcp package version in non CPM project Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * chore: add ModelContextProtocol.Extensions.Tasks package reference Signed-off-by: Vincent Biret <vibiret@microsoft.com> * tests: updates integration tests following dependency upgrade --------- Signed-off-by: Vincent Biret <vibiret@microsoft.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…icrosoft#8290) * Limit MCP skill archives to the ZIP format Skill archives served over MCP are restricted to ZIP in both .NET and Python. Payloads detected as any other container format are reported as unsupported and skipped during discovery instead of being unpacked. - .NET: drop `ArchiveFormat.Tar`/`TarGz` and the TAR extraction path from `AgentMcpSkillArchiveExtractor`; an unsupported format now throws before the target directory is created. - Python: drop `_ArchiveFormat.TAR`/`TAR_GZ` and `_extract_tar_to_memory` from `_skills.py`; an unsupported format raises. - Update the affected unit tests and documentation to match. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Address review feedback - Drop redundant `@pytest.mark.asyncio` decorators: `packages/core` configures `asyncio_mode = "auto"`, so pytest-asyncio collects the async tests without them. - Update the `FoundryToolbox.as_skills_provider()` docstring to describe archive entries as ZIP, matching the source it forwards options to. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Simplify CODEOWNERS rules Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6f2020a7-d92e-4a6b-8a5d-1b05cdbabda6 * Clarify CODEOWNERS rule scope Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6f2020a7-d92e-4a6b-8a5d-1b05cdbabda6 --------- Copilot-Session: 6f2020a7-d92e-4a6b-8a5d-1b05cdbabda6
* Python: Isolate Anthropic request parsing state Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Python: Cover concurrent Anthropic responses Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Python: Scope Redis history storage keys Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Python: Address Redis history review feedback Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b9da797e-a9ff-492f-b5c1-8e9c7af1d8dc
* Python: scope Secure MCP URL headers to origin Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>\nCopilot-Session: bf1fc8c4-eff7-42e7-9342-d385036223be * Python: preserve concurrent Secure MCP calls Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>\nCopilot-Session: bf1fc8c4-eff7-42e7-9342-d385036223be
* fix: race concdition in workflow formula state * fix: build issue with key
* chore: update Microsoft.Testing.Extensions.CodeCoverage to version 18.11.2 Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update Microsoft.Identity.Client.Extensions.Msal to version 4.89.0 Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update Microsoft.Agents.AI.Foundry to version 1.5.0 Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update Google.GenAI to version 1.21.0 Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update Microsoft.ML.OnnxRuntimeGenAI to version 0.15.2 Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update Microsoft.Agents.CopilotStudio.Client and related packages to version 1.9.35-beta Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update Microsoft.Agents.AI to version 1.20.0 and Microsoft.Extensions.Hosting to version 10.0.12 Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update AgentFrameworkVersion to 1.20.0-preview.260831.1 Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update AgentFrameworkVersion to 1.20.0 and Azure.AI.AgentServer.Invocations to version 1.0.0-beta.7 Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update Aspire.Azure.AI.OpenAI to version 13.5.3-preview.1.26425.3 Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update Mscc.GenerativeAI.Microsoft to version 3.1.0 Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update Microsoft.CodeAnalysis.Analyzers and Microsoft.CodeAnalysis.CSharp to version 5.9.0 Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update Neo4j.Driver to version 6.3.0 Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: update System.CommandLine to version 2.0.12 Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: downgrade Neo4j.Driver to version 5.28.0 Signed-off-by: Vincent Biret <vibiret@microsoft.com> * chore: Downgrade Microsoft.Agents.AI package version to maintain alignment Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Signed-off-by: Vincent Biret <vibiret@microsoft.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…ft#8301) * fix: inspect for delemiter value before adding headers * chore: Simplify error message for invalid HTTP header name Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * test: Cover invalid body content type rejection Co-authored-by: baywet <7905502+baywet@users.noreply.github.com> * fix: address CRLF test build issue Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 241dc909-4fc9-4e7c-8f7c-fb969e4ce2e9 --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: baywet <7905502+baywet@users.noreply.github.com> Copilot-Session: 241dc909-4fc9-4e7c-8f7c-fb969e4ce2e9
Co-authored-by: mrchatam <mrchatam@users.noreply.github.com>
) * Python: Make HTTP response-cookie persistence explicit Configure internally created MCP, A2A, and AG-UI HTTP clients to reject response-cookie persistence while preserving caller-provided clients. Retain connection reuse and cleanup, and document the migration path for applications requiring persistent cookies. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Align declarative HTTP cookie persistence defaults Apply the default response-cookie policy to internally managed declarative HTTP clients. Preserve supplied and provider-returned clients, client selection and lifecycle, explicit request headers, and response headers. Document the configuration path and cover reuse, failure responses, and overlapping requests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Preserve caller-owned A2A HTTP clients Leave HTTP clients supplied alongside an A2A protocol client open on agent exit. Extend the existing ownership regression, retain internally owned cleanup coverage, and document caller cleanup responsibility. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Clarify AG-UI test types Type conditional exception contexts explicitly and use separate variables for chat and HTTP responses. Preserve the existing test cases and assertions while satisfying Mypy and Zuban. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…bstractions (microsoft#7991) * feat(dotnet): share agent session store abstraction * fix(dotnet): address session store review findings * fix(dotnet): remove legacy session key fallback * feat(dotnet): add partitioned session store keys * refactor(dotnet): keep session keys storage agnostic * refactor(dotnet): promote delegating session store * Restore session store service discovery Preserve GetService in the shared contract and delegate service queries through store decorators. Use discovery to avoid duplicate isolation wrappers in Hosting, A2A, and AGUI. Update public APIs, documentation, and regression coverage with scoped RS0026 pragmas. Copilot-Session: 22c59c1d-1805-41b5-b868-c01855e7ceb7 * Avoid dictionary allocations for unpartitioned session keys Make AgentSessionStoreKey.Partitions nullable and normalize absent or empty partitions to null. Update equality, hashing, storage encoders, API declarations, and regression tests. Copilot-Session: 22c59c1d-1805-41b5-b868-c01855e7ceb7 --------- Copilot-Session: 22c59c1d-1805-41b5-b868-c01855e7ceb7
…sent (microsoft#8274) * fix(mcp): do not duplicate structuredContent when content present Fixes microsoft#7866. Prefer content blocks for model-visible tool results; structuredContent remains on the Host payload. Serialize structuredContent only when content is empty. * test(mcp): align expectations with single content+structured item Address Copilot review on microsoft#8274: update suites that still expected the old duplicated model-visible content shape. * fix(mcp): add explicit tool_result_content selection policy Replace hard-coded content-first behavior with structured_first/content_first/content_only/structured_only/both, defaulting to structured_first per microsoft#7866 discussion. * fix(mcp): document tool_result_content and tighten test typing Add undocumented-param docstring entries on MCP transport constructors and assert tool result text before json.loads.
Apply the existing transport-argument restriction to both options and client_kwargs. Add mock-transport regression coverage while preserving constructor configuration and normal generation options. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Python: Propagate runtime arguments to skill callbacks Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Python: Pass runtime mappings through skill helpers Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Python: Specify agent options type in skill tests Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* fix: preserve hosted session key boundaries Signed-off-by: Ricky-7-Yan <2314530442@qq.com> * test(hosting): extend session key harness Cover identifier boundaries, escaping, streaming, and session reuse. Fix missing test imports and document opaque hosted identifiers. Refs microsoft#8251 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 165465df-61e4-45eb-a147-08b425b4f5bd * perf(hosting): reuse composite session keys Use tuple lookups in the session harness to avoid serialization and throwaway session construction on cache hits. Preserve existing JSON session identifiers by encoding only when a session is created. Refs microsoft#8251 * docs(hosting): keep composite session IDs opaque Describe the identifier contract without exposing its internal representation as a compatibility guarantee. Refs microsoft#8251 --------- Signed-off-by: Ricky-7-Yan <2314530442@qq.com> Co-authored-by: Roger Barreto <19890735+RogerBarreto@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 165465df-61e4-45eb-a147-08b425b4f5bd
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Python: Require unambiguous MCP configuration names Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1f64c925-132e-4d46-865d-d5c05e218074 * Fix MCP tool snapshot replacement on refresh * Fix MCP refresh test typing and formatting --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1f64c925-132e-4d46-865d-d5c05e218074
* Python: Handle provider-invalidated function calls Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Python: Simplify invalidated call cleanup Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Python: Rename response invalidation exception Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Python: Raise Anthropic Core dependency floor Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Apply Anthropic formatting Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Python: Address response invalidation review Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Python: add public API compatibility workflow Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d1fa3e1a-596f-446f-b77f-5c84ec1eaa38 * Python: address API compatibility review feedback Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d1fa3e1a-596f-446f-b77f-5c84ec1eaa38 * Python: align API checks with merge refs and stages Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d1fa3e1a-596f-446f-b77f-5c84ec1eaa38 * CI: validate API compatibility workflow edits Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d1fa3e1a-596f-446f-b77f-5c84ec1eaa38 * CI: separate breaking intent from approval Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d1fa3e1a-596f-446f-b77f-5c84ec1eaa38 --------- Copilot-Session: d1fa3e1a-596f-446f-b77f-5c84ec1eaa38
* Python: Deprecate MCP sampling callback * Python: Warn when configuring MCP sampling * Python: Keep sampling tests type-safe
* Add stable names to orchestration workflows * Add orchestration workflow name tests * Assert stable names in checkpoint tests --------- Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
…a shared temp path (microsoft#7757) * Python: fix: make concurrent FileCheckpointStorage saves not race on a shared temp path FileCheckpointStorage.save() wrote to and then renamed a fixed "<checkpoint-id>.json.tmp" path, so concurrent saves of the same checkpoint ID raced over the shared temp file. Whichever save renamed first removed the temp file still being written by another save, which then failed with FileNotFoundError / PermissionError in os.replace. Create a unique temp file per save in the destination directory (so os.replace remains atomic), serialize same-ID writes with a per-ID lock, and retry the atomic move briefly to absorb the transient Windows background-handle PermissionError that surfaces even for fully serialized replaces. Fixes microsoft#7748 * Python: fix: lock file writes at destination path, shield workers from cancellation Address two post-merge review concerns on FileCheckpointStorage.save(): - The per-event-loop, per-instance asyncio.Lock registry could not serialize two FileCheckpointStorage instances pointed at the same directory, nor a single instance driven from two event loops. Replace it with a process-wide, per-canonical-path threading.Lock registry (lazily populated, bounded by distinct destinations actually written). Because asyncio.to_thread runs the actual file I/O on a worker thread, the threading lock serializes correctly across coroutines, loops, and instances and spans the entire open + write + os.replace window. - Caller-side cancellation previously released the write lock early: a CancelledError delivered inside 'await asyncio.to_thread(...)' exited the 'async with' and ran _release_save_lock_ref while the OS thread kept writing. The next save for the same checkpoint_id could then reach os.replace concurrently, reintroducing the PermissionError race and possibly landing stale data over a newer write. Shield the worker so cancellation propagates only after the in-flight write completes. Also replace the refcount-aware registry test with: - registry-bounded test for the new invariant (one lock per destination) - cross-instance concurrent save test (two storages, same directory) - gated os.replace cancel-race test (deterministically parks A's worker mid-publish, confirms save B cannot reach os.replace until A completes) Fixes microsoft#7748 * Python: take checkpoint destination ownership before submitting the write Implements the revised A shape chosen in review: process-wide coordination keyed by canonical destination, asynchronous waiters, and registry entries released after the final queued or running operation. Three review findings shared one cause -- ownership was established inside the executor thread rather than before submission. Acquiring the destination lock inside the worker meant every same-path save occupied an `asyncio.to_thread` worker while merely waiting, so a burst could fill the default pool and stall unrelated work including checkpoint loads, and could deadlock once the write that had to finish first was queued behind those waiters. Ownership now comes from a queue keyed by the canonical path and is taken before the write is submitted, so only the active write holds a worker. Waiters suspend on `asyncio.wrap_future` over a `concurrent.futures.Future`, which is not bound to a loop, so one chain also orders writers enqueued from different event loops -- something a per-path lock could not do. The registry was a dict that never removed an entry. Because `WorkflowCheckpoint` generates a fresh UUID by default, every save retained one entry for the life of the process. Entries are now reference-counted by queued-or-running operations and dropped by the last release. Cancellation is handled explicitly, both ways the review allowed. A save cancelled while still waiting for the destination has nothing in the executor, so it is simply removed -- and it still hands ownership on, or every later save for that path would wait forever. A save cancelled mid-write drains its worker before propagating, because releasing first would let the next save start while this replace is still in flight. That drain absorbs re-delivered cancellations: once a task has a cancellation pending its next await raises immediately, so a single shielded await returns with the worker still running and the write can still land after ownership is released. Ownership is released as the write's last act on the worker thread, with the coroutine's `finally` as a backstop for the case where no write was submitted. Releasing only from the coroutine regressed on the design it replaced: a `threading.Lock` was released by the worker thread, which outlives the loop that submitted it, whereas a coroutine that never resumes -- its loop closed with the task still pending -- would leave the destination owned for the life of the process and hang every later save to it. The two releasers are idempotent, so exactly one of them accounts for each ticket. Tests are deterministic and cover each case: registry release for repeated, distinct-ID and concurrent saves; queued saves not occupying executor threads, gated by a two-worker executor with three saves in flight; serialization across two real event loops; cancellation before submission writing nothing and not stalling the follower; repeated cancellation still draining; a write failing while draining being reported rather than lost; a failed save releasing its destination and leaving the path usable; recovery of a destination whose loop was closed mid-write; and the defensive release path. * Python: tie checkpoint write ownership to the write, not to asyncio state Follow-up review on microsoft#7757 found two ways a later save could still overtake an earlier one. Both had the same cause: asyncio objects were standing in for the state of work that lives outside asyncio, and cancellation can mark those done while the work continues. `asyncio.wrap_future` chains cancellation into the future it wraps. Cancelling the middle of three queued saves therefore cancelled the hand-off signal the first save still had to resolve, and the unconditional release then let the third reach `os.replace` beside the first -- after which the first write could land last and overwrite the newer checkpoint. Waiting now goes through `_wait_for_signal`, which feeds a fresh per-wait future from a done-callback and leaves the shared signal untouched no matter what happens to the waiter. A save cancelled while queued no longer resolves its own signal either; it defers the hand-off until its predecessor has actually finished, so the queue stays ordered while still guaranteeing nothing waits behind it forever. Draining on the task wrapping `asyncio.to_thread` was the second: a cancelled task reports `done()` while its function is still inside `os.replace`, so loop shutdown released ownership with the write in flight. The drain now waits on the signal the worker thread resolves, which cancellation cannot mark done. Fixing those exposed two more failures of the same kind, both found by probing rather than by review. `ensure_future(asyncio.to_thread(...))` makes the write a Task, and shutdown cancels every task -- possibly before it reaches the executor. Nothing then released the destination, and the drain waited for a signal that could never be resolved, so the save never completed at all. The write is now submitted with `run_in_executor`, which submits synchronously and returns a plain Future that `asyncio.all_tasks()` does not include, plus a done-callback that releases on success, failure and cancellation alike. Deferring a cancelled ticket's hand-off onto its predecessor made release recursive: resolving one signal ran the next ticket's callback synchronously, so a run of cancelled queued saves longer than the recursion limit raised `RecursionError` on the worker thread partway through and left the destination owned for good. Releases are now collected per thread and drained in a loop, so the depth is flat however long the run. Two smaller points from the same review. A write that fails while draining is recorded on the ticket rather than read back from the worker future, because a cancelled task hides its own exception and the cancelled caller never sees it. And the drain registers one done-callback pointing at whichever waiter is current, rather than one per wait, so a caller cancelling in a loop no longer grows that list in step with it. Tests: cancelling the middle of three queued saves cannot let the third overtake; a cancelled worker task does not release while the thread writes; shutdown before the write starts neither hangs nor strands the destination, asserted structurally on the write not being a task so the regression fails cleanly instead of hanging CI; a deferred-release run of 2000 links does not recurse; submission against a dead executor releases; and resolving a signal after its loop closed does not raise. * Python: release a queued checkpoint save whose event loop is abandoned Follow-up review on microsoft#7757. A submitted write is released by its worker thread, which outlives the loop that submitted it, but a ticket still waiting for its predecessor has no worker to fall back on. If that waiter's loop closes, `call_soon_threadsafe` raises `RuntimeError`, the suppression swallowed it, and the coroutine never resumed -- so nothing resolved the ticket's hand-off signal and every later save for that destination waited forever. Reproduced: the entry stays at `pending=1` and a later save from a fresh loop times out. The predecessor's callback now owns that case. `_wait_for_signal` takes an `on_abandoned` hook, invoked when the waiter's loop has closed, and the queued wait passes its own release -- performed on the thread that resolved the predecessor rather than on a loop that will never run again. The drain keeps suppressing, and the two guards now differ deliberately: by the time anything drains, the write has been submitted, so the worker thread and the submitted future's callback both release without needing that loop. The comment says so, since the asymmetry is otherwise unexplained. Two windows this cannot close, both stated in the comment rather than implied: a loop that closes after `call_soon_threadsafe` succeeded but before the callback runs, and one abandoned without being closed at all. Reaching either needs a loop closed with tasks still pending, which asyncio already reports as an error. Graceful shutdown is unaffected -- `asyncio.run` cancels pending tasks first, which drives a queued save through its cancellation path and defers the hand-off onto its predecessor. That path now has its own test, since it is the guarantee callers actually depend on. * Python: cover the checkpoint write error paths this PR introduced Three branches added by this PR had no test. Coverage of `_checkpoint.py` was reporting 97% with the gaps sitting exactly on the error handling: * the bounded `os.replace` retry giving up after five attempts. The suite only ever reached the surrounding lines by accident -- the concurrency tests trip a real `PermissionError` on Windows now and then, which is environment-dependent and never happens on Linux CI. The new test pins both halves that matter: the retry is bounded, and giving up still releases the destination rather than wedging every later save to it. * the temp-file cleanup swallowing an `OSError`. It runs in a `finally` while a write exception is propagating, so letting one out would substitute a misleading "cannot remove temp file" for the real disk failure. Reverting the handler makes the new test fail with exactly that substitution. * the fast path in `_await_signal_through_cancellation` for a signal that has already resolved. Exercised directly, since arranging the race through `save()` is not deterministic. No source change. Every line this PR adds is now covered; the three that remain uncovered in the file all predate it. * Python: correct two test docstrings that still described the superseded design Copilot review on microsoft#7757. Both described machinery this PR replaced, which would point the next reader at the wrong design. The cross-instance test said the fix "switched to a process-wide, per-destination threading.Lock keyed by canonical path". Ownership comes from a process-wide queue keyed by the canonical destination path; the lock is what it replaced. The cross-loop test was worse: it said the hand-off signal is one "any loop can await through `asyncio.wrap_future`". That is the mechanism this PR deliberately does not use -- it chains a waiter's cancellation into the shared signal an earlier writer still has to resolve, which is the defect the review caught earlier on this PR. It now names `_wait_for_signal` and says why `wrap_future` is excluded. Checked the file's other references: the remaining `threading.Lock` and `wrap_future` mentions are either locks used by the tests themselves or past-tense descriptions of what was replaced, which are accurate as written. * Python: hold the abandoned-loop tests' pending tasks instead of letting GC decide `test_file_checkpoint_storage_abandonment_mid_chain_keeps_the_queue_ordered` crashed a Windows CI worker. Not an assertion failure -- the worker process died, with no Python traceback. The cause is an unreferenced pending task. The test did `abandoned_loop.create_task(storage.save(...))` without keeping the result, so the task was collectable the moment the call returned, and the loop it belongs to is deliberately closed while the task is still pending. That left the task's finalizer -- which touches the closed loop -- to run at whatever point the garbage collector chose, including during worker teardown. That also explains the shape of the failure. It is not a version boundary: 3.11, 3.12 and 3.14 failed on Windows while 3.10 and 3.13 passed, and every Linux job passed. Non-monotonic scatter like that is a timing flake, and GC timing is the thing that varies. It did not reproduce locally in ten runs on 3.12 -- the test alone, the file under xdist, the workflow directory, and the full core suite under xdist six times. Three sibling tests had the same unreferenced-task pattern, all of them in tests that abandon or shut down a loop on purpose, so all four now hold their tasks for the duration of the test. The sibling at `test_file_checkpoint_storage_abandoned_loop_while_queued_releases_the_destination` already did this correctly, which is what made the inconsistency visible. Holding the reference does not weaken what these tests prove: the abandonment being tested is of the loop, not of the task object, and the task stays pending either way. It only moves the finalizer to a deterministic point. * Python: stop the shutdown test racing the filesystem CI failed with `found 0 tasks` on Linux 3.13. Not the code -- the test's timing assumption. It created the save task, yielded once with `await asyncio.sleep(0)`, then asserted exactly one pending task to prove the write is not itself a task. But a single yield drains every ready callback, so on a fast tmpfs the executor write could finish and resolve the shield inside that same batch; the save completed and `asyncio.all_tasks()` came back empty. The write is now held at its first syscall, so the save is deterministically suspended when the count is taken. Three things about the gate matter: * It only gates this save's own temp file. `checkpoint_module.os` is the real `os` module, so the patch is process-wide, and blocking every `os.open` would stall pytest's own I/O and coverage writes on the same event and deadlock the run. * The assertions are split. An empty list now reports that the gate did not hold, which is a problem with the test; two tasks reports the write being a task, which is the regression. One message could not honestly explain both, and `0` was indistinguishable from the flake it replaced. * A failing assertion releases the worker before propagating, so the real error surfaces immediately instead of after the gate's timeout. Verified rather than assumed: reverting the source to `ensure_future(asyncio.to_thread(...))` still fails the test, now with `found 2 tasks` and the pending `to_thread()` task in the output. Stable over ten runs of the test and five shuffled xdist runs of the whole file. --------- Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
Co-authored-by: WhaleTech <304937387+ryo-whaletech@users.noreply.github.com>
Co-authored-by: WhaleTech <304937387+ryo-whaletech@users.noreply.github.com>
…the python-type-checkers group (microsoft#8249) * Build(deps-dev): bump ty in /python in the python-type-checkers group Bumps the python-type-checkers group in /python with 1 update: [ty](https://github.com/astral-sh/ty). Updates `ty` from 0.0.77 to 0.0.78 - [Release notes](https://github.com/astral-sh/ty/releases) - [Changelog](https://github.com/astral-sh/ty/blob/main/CHANGELOG.md) - [Commits](astral-sh/ty@0.0.77...0.0.78) --- updated-dependencies: - dependency-name: ty dependency-version: 0.0.78 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: python-type-checkers ... Signed-off-by: dependabot[bot] <support@github.com> * Fix ty dependency update checks Co-authored-by: eavanvalkenburg <13749212+eavanvalkenburg@users.noreply.github.com> * Fix checkpoint queue release deadlock --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: eavanvalkenburg <13749212+eavanvalkenburg@users.noreply.github.com> Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com> Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com> Co-authored-by: Evan Mattson <evan.mattson@microsoft.com>
* CI: safely inspect fork API changes Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d1fa3e1a-596f-446f-b77f-5c84ec1eaa38 * CI: narrow API attribute filtering Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d1fa3e1a-596f-446f-b77f-5c84ec1eaa38 --------- Copilot-Session: d1fa3e1a-596f-446f-b77f-5c84ec1eaa38
…es (microsoft#8405) When one assistant turn contains text, tool calls and reasoning, the Chat Completions serializer emitted two assistant dicts (text-only, then tool_calls) and the buffered reasoning field only travelled with the second one. OpenAI-compatible providers such as DeepSeek in thinking mode reject the tool-result follow-up because the message that carries the content no longer carries its reasoning. Attach the tool calls of a turn to the assistant dict built from that turn's plain text (and text that follows coalesced tool calls to the tool_calls dict), so content, tool_calls and the reasoning field are sent as a single assistant message. Reasoning text surfaced via the response_parser hook keeps its own dict so message_preparer correlation is unchanged; refusals, images and other content are not merged. Fixes microsoft#8382 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
Create and clean up separate MCP sessions for custom client-provider calls in .NET and Python. Preserve default session caching and caller-owned HTTP clients, and add lifecycle coverage and compatibility guidance. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
jpalvarezl
had a problem deploying
to
github-app-auth
September 16, 2026 10:29 — with
GitHub Actions
Failure
jpalvarezl
had a problem deploying
to
github-app-auth
September 16, 2026 10:29 — with
GitHub Actions
Failure
jpalvarezl
had a problem deploying
to
github-app-auth
September 16, 2026 10:29 — with
GitHub Actions
Failure
This branch had an error being deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation & Context
Make MCP session ownership explicit for declarative workflow handlers that use custom HTTP client providers. Provider-selected authentication is not represented in the existing session cache key, so that key alone cannot establish whether a previous session is appropriate for each invocation.
Description & Review Guide
tools/listand when the provider returns the same HTTP client ornull/None. Sessions and owned fallback transports are cleaned up after use, active provider-backed invocations are tracked during shutdown, and caller-owned HTTP clients remain open. Existing no-provider session caching is preserved. Documentation and in-memory functional regression tests cover the ownership and lifecycle contract.Related Issue
N/A
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.