diff --git a/.github/workflows/python-integration-tests.yml b/.github/workflows/python-integration-tests.yml
index a73fb6916b..8c74f21130 100644
--- a/.github/workflows/python-integration-tests.yml
+++ b/.github/workflows/python-integration-tests.yml
@@ -369,6 +369,53 @@ jobs:
path: ./python/pytest.xml
if-no-files-found: ignore
+ # Foundry Hosting integration tests
+ python-tests-foundry-hosting:
+ name: Python Integration Tests - Foundry Hosting
+ runs-on: ubuntu-latest
+ environment: integration
+ timeout-minutes: 60
+ env:
+ FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }}
+ FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL }}
+ defaults:
+ run:
+ working-directory: python
+ steps:
+ - uses: actions/checkout@v6
+ with:
+ ref: ${{ inputs.checkout-ref }}
+ persist-credentials: false
+ - name: Set up python and install the project
+ id: python-setup
+ uses: ./.github/actions/python-setup
+ with:
+ python-version: ${{ env.UV_PYTHON }}
+ os: ${{ runner.os }}
+ - name: Azure CLI Login
+ uses: azure/login@v2
+ with:
+ client-id: ${{ secrets.AZURE_CLIENT_ID }}
+ tenant-id: ${{ secrets.AZURE_TENANT_ID }}
+ subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
+ - name: Test with pytest (Foundry Hosting integration)
+ timeout-minutes: 15
+ run: >
+ uv run pytest --import-mode=importlib
+ packages/foundry_hosting/tests
+ -m integration
+ -n logical --dist worksteal
+ --timeout=120 --session-timeout=900 --timeout_method thread
+ --retries 2 --retry-delay 5
+ --junitxml=pytest.xml
+ - name: Upload test results
+ if: always()
+ uses: actions/upload-artifact@v7
+ with:
+ name: test-results-foundry-hosting
+ path: ./python/pytest.xml
+ if-no-files-found: ignore
+
# Azure Cosmos integration tests
python-tests-cosmos:
name: Python Integration Tests - Cosmos
@@ -435,6 +482,7 @@ jobs:
python-tests-misc-integration,
python-tests-functions,
python-tests-foundry,
+ python-tests-foundry-hosting,
python-tests-cosmos,
]
runs-on: ubuntu-latest
@@ -498,6 +546,7 @@ jobs:
python-tests-misc-integration,
python-tests-functions,
python-tests-foundry,
+ python-tests-foundry-hosting,
python-tests-cosmos
]
steps:
diff --git a/.github/workflows/python-merge-tests.yml b/.github/workflows/python-merge-tests.yml
index 0513f47a2e..1ad5019951 100644
--- a/.github/workflows/python-merge-tests.yml
+++ b/.github/workflows/python-merge-tests.yml
@@ -38,6 +38,7 @@ jobs:
miscChanged: ${{ steps.filter.outputs.misc }}
functionsChanged: ${{ steps.filter.outputs.functions }}
foundryChanged: ${{ steps.filter.outputs.foundry }}
+ foundryHostingChanged: ${{ steps.filter.outputs.foundry_hosting }}
cosmosChanged: ${{ steps.filter.outputs.cosmos }}
steps:
- uses: actions/checkout@v6
@@ -80,6 +81,8 @@ jobs:
- 'python/packages/foundry/**'
- 'python/samples/**/providers/foundry/**'
- 'python/samples/02-agents/embeddings/foundry_embeddings.py'
+ foundry_hosting:
+ - 'python/packages/foundry_hosting/**'
cosmos:
- 'python/packages/azure-cosmos/**'
# run only if 'python' files were changed
@@ -521,6 +524,67 @@ jobs:
path: ./python/pytest.xml
if-no-files-found: ignore
+ # Foundry Hosting integration tests
+ python-tests-foundry-hosting:
+ name: Python Tests - Foundry Hosting Integration
+ needs: paths-filter
+ if: >
+ github.event_name != 'pull_request' &&
+ needs.paths-filter.outputs.pythonChanges == 'true' &&
+ (github.event_name != 'merge_group' ||
+ needs.paths-filter.outputs.foundryHostingChanged == 'true' ||
+ needs.paths-filter.outputs.coreChanged == 'true')
+ runs-on: ubuntu-latest
+ environment: integration
+ env:
+ FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }}
+ FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL }}
+ defaults:
+ run:
+ working-directory: python
+ steps:
+ - uses: actions/checkout@v6
+ - name: Set up python and install the project
+ id: python-setup
+ uses: ./.github/actions/python-setup
+ with:
+ python-version: ${{ env.UV_PYTHON }}
+ os: ${{ runner.os }}
+ - name: Azure CLI Login
+ if: github.event_name != 'pull_request'
+ uses: azure/login@v2
+ with:
+ client-id: ${{ secrets.AZURE_CLIENT_ID }}
+ tenant-id: ${{ secrets.AZURE_TENANT_ID }}
+ subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
+ - name: Test with pytest (Foundry Hosting integration)
+ timeout-minutes: 15
+ run: >
+ uv run pytest --import-mode=importlib
+ packages/foundry_hosting/tests
+ -m integration
+ -n logical --dist worksteal
+ --timeout=120 --session-timeout=900 --timeout_method thread
+ --retries 2 --retry-delay 5
+ --junitxml=pytest.xml
+ working-directory: ./python
+ - name: Surface failing tests
+ if: always()
+ uses: pmeier/pytest-results-action@v0.7.2
+ with:
+ path: ./python/pytest.xml
+ summary: true
+ display-options: fEX
+ fail-on-empty: false
+ title: Foundry Hosting integration test results
+ - name: Upload test results
+ if: always()
+ uses: actions/upload-artifact@v7
+ with:
+ name: test-results-foundry-hosting
+ path: ./python/pytest.xml
+ if-no-files-found: ignore
+
# TODO: Add python-tests-lab
# Azure Cosmos integration tests
@@ -602,6 +666,7 @@ jobs:
python-tests-misc-integration,
python-tests-functions,
python-tests-foundry,
+ python-tests-foundry-hosting,
python-tests-cosmos,
]
runs-on: ubuntu-latest
@@ -662,6 +727,7 @@ jobs:
python-tests-misc-integration,
python-tests-functions,
python-tests-foundry,
+ python-tests-foundry-hosting,
python-tests-cosmos,
]
steps:
diff --git a/.gitignore b/.gitignore
index da436cd090..283f626207 100644
--- a/.gitignore
+++ b/.gitignore
@@ -242,3 +242,7 @@ python/dotnet-ref
# Generated filtered solution files (created by eng/scripts/New-FilteredSolution.ps1)
dotnet/filtered-*.slnx
**/*.lscache
+
+# Local tool state
+.omc/
+.omx/
diff --git a/dotnet/Directory.Packages.props b/dotnet/Directory.Packages.props
index fff7b6a7d4..c57af55ef9 100644
--- a/dotnet/Directory.Packages.props
+++ b/dotnet/Directory.Packages.props
@@ -56,15 +56,15 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/samples/02-agents/AgentSkills/SubprocessScriptRunner.cs b/dotnet/samples/02-agents/AgentSkills/SubprocessScriptRunner.cs
index e95bde61df..b2068c4c0b 100644
--- a/dotnet/samples/02-agents/AgentSkills/SubprocessScriptRunner.cs
+++ b/dotnet/samples/02-agents/AgentSkills/SubprocessScriptRunner.cs
@@ -5,16 +5,16 @@
// This is provided for demonstration purposes only.
using System.Diagnostics;
+using System.Text.Json;
using Microsoft.Agents.AI;
-using Microsoft.Extensions.AI;
///
/// Executes file-based skill scripts as local subprocesses.
///
///
-/// This runner uses the script's absolute path, converts the arguments
-/// to CLI flags, and returns captured output. It is intended for
-/// demonstration purposes only.
+/// This runner uses the script's absolute path and converts the arguments
+/// to CLI arguments. When the LLM sends a JSON array, each element is used
+/// as a positional argument. It is intended for demonstration purposes only.
///
internal static class SubprocessScriptRunner
{
@@ -24,7 +24,8 @@ internal static class SubprocessScriptRunner
public static async Task