Skip to content

Add Foundry hosted agent protocol selection - #17732

Merged
David Fowler (davidfowl) merged 4 commits into
release/13.4from
davidfowl/foundry-protocol
May 31, 2026
Merged

Add Foundry hosted agent protocol selection#17732
David Fowler (davidfowl) merged 4 commits into
release/13.4from
davidfowl/foundry-protocol

Conversation

@davidfowl

Copy link
Copy Markdown
Collaborator

Description

Foundry hosted agents need to carry the selected protocol through both local development and Azure publish output so users can validate agents that use either the responses or invocations protocol. This adds protocol-aware run-mode dashboard commands and publishes configured container_protocol_versions, while keeping C# on the existing Action<HostedAgentConfiguration> configuration path.

TypeScript/polyglot AppHosts can set protocols through the exported hosted agent options DTO because that path cannot expose Azure SDK types directly.

User-facing usage

C# AppHost:

agent.AsHostedAgent(project, configuration =>
{
    configuration.ContainerProtocolVersions.Clear();
    configuration.ContainerProtocolVersions.Add(new ProtocolVersionRecord(ProjectsAgentProtocol.Invocations, "1.0.0"));
});

TypeScript AppHost:

hostedAgent.asHostedAgent(project, {
  protocols: [{ protocol: 'invocations', version: '1.0.0' }]
});

Validation

./restore.sh
dotnet test --project tests/Aspire.Hosting.Foundry.Tests/Aspire.Hosting.Foundry.Tests.csproj --no-launch-profile -- --filter-class "*.HostedAgentExtensionTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"

Fixes #17730

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No

Support configuring Foundry hosted agent protocols for publish output and local run-mode dashboard commands, including TypeScript AppHost coverage for the exported DTO shape.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented May 30, 2026

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 17732

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17732"

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class protocol selection for Microsoft Foundry hosted agents so the selected ingress protocol is carried through both local run-mode dashboard interactions and publish output, enabling validation for either the responses or invocations protocol (including from TypeScript/polyglot AppHosts).

Changes:

  • Adds protocol-aware run-mode URL labeling, HTTP command path selection, and request/response handling for hosted agents.
  • Extends the polyglot-exported hosted agent options DTO with protocols and maps it to ContainerProtocolVersions for publish output.
  • Adds coverage in Foundry hosting tests and the TypeScript validation AppHost for the invocations protocol path.
Show a summary per file
File Description
tests/PolyglotAppHosts/Aspire.Hosting.Foundry/TypeScript/apphost.mts Adds /invocations endpoint handling and sets protocols in the exported hosted agent options for validation.
tests/Aspire.Hosting.Foundry.Tests/HostedAgentExtensionTests.cs Adds run-mode and options-mapping tests validating invocations protocol selection.
src/Aspire.Hosting.Foundry/HostedAgent/HostedAgentOptions.cs Introduces Protocols DTO and maps it onto Azure SDK ContainerProtocolVersions with validation.
src/Aspire.Hosting.Foundry/HostedAgent/HostedAgentBuilderExtension.cs Makes run-mode commands/URLs protocol-aware and threads configuration through run/publish paths.

Copilot's findings

  • Files reviewed: 4/4 changed files
  • Comments generated: 3

Comment thread src/Aspire.Hosting.Foundry/HostedAgent/HostedAgentOptions.cs
Comment thread src/Aspire.Hosting.Foundry/HostedAgent/HostedAgentOptions.cs
Improve hosted agent protocol validation parameter names and add run-mode context when configuration callbacks fail during protocol inference.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@davidfowl

David Fowler (davidfowl) commented May 30, 2026

Copy link
Copy Markdown
Collaborator Author

PR #17732 Foundry hosted-agent deployment validation

PR build under test

  • CLI: 13.4.0-pr.17732.gb65cc47f
  • Expected PR head: b65cc47f66a6eda2a02fe86ccaf1b0e8889755c9
  • Installed CLI: PR dogfood CLI in an isolated temporary test directory
  • Temporary AppHost: isolated temporary test directory

Scenario

Created a temporary C# file-based AppHost using the PR build and Aspire.Hosting.Foundry.
The AppHost deploys a Dockerfile resource as a Foundry hosted agent and configures the C# API through Action<HostedAgentConfiguration>:

configuration.ContainerProtocolVersions.Clear();
configuration.ContainerProtocolVersions.Add(new ProtocolVersionRecord(ProjectsAgentProtocol.Invocations, "1.0.0"));

Deployment result

  • aspire deploy --apphost apphost.cs --environment Pr17732WestUS3 --clear-cache --non-interactive
  • Target: Azure Foundry hosted agent service
  • Location: westus3
  • Result: succeeded, 23/23 steps passed.

The first attempt in eastus successfully provisioned Foundry resources and pushed the image, but Foundry rejected the hosted-agent deployment with Unsupported region for Foundry Hosted Agents. Retrying in westus3 completed successfully.

Verification

Listed the deployed agents through the Foundry Agents REST API:

{
  "id": "hosted-agent-ha:2",
  "status": "active",
  "protocols": [
    {
      "protocol": "invocations",
      "version": "1.0.0"
    }
  ]
}

Invoked the deployed hosted agent through the Foundry invocations endpoint:

POST /agents/hosted-agent-ha/endpoint/protocols/invocations?api-version=v1
HTTP/2 200

{"response":"hello from deployed PR 17732 hosted agent"}

Checked that the responses endpoint is not exposed for the invocations-only agent:

POST /agents/hosted-agent-ha/endpoint/protocols/openai/responses?api-version=v1
HTTP/2 400

The service returned: Endpoint-scoped responses require the 'responses' protocol to be declared in container_protocol_versions for agent 'hosted-agent-ha:2'.

Cleanup status

Temporary Azure resources created for this validation were deleted after the run.

Update hosted agent deployment to patch the Foundry agent endpoint protocols after creating a hosted-agent version, so endpoint routing matches the configured container protocol versions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@davidfowl

Copy link
Copy Markdown
Collaborator Author

PR Testing Report

PR Information

CLI Version Verification

  • Expected Commit: d5a3619
  • Installed Version: 13.4.0-pr.17732.gd5a36197
  • Status: Verified

Changes Analyzed

Files Changed

  • src/Aspire.Hosting.Foundry/HostedAgent/HostedAgentBuilderExtension.cs
  • src/Aspire.Hosting.Foundry/HostedAgent/HostedAgentOptions.cs
  • src/Aspire.Hosting.Foundry/HostedAgent/AzureHostedAgentResource.cs
  • tests/Aspire.Hosting.Foundry.Tests/HostedAgentExtensionTests.cs
  • tests/PolyglotAppHosts/Aspire.Hosting.Foundry/TypeScript/apphost.mts

Change Categories

  • CLI changes detected
  • Hosting integration changes
  • Dashboard changes
  • Template changes
  • Client/Component changes
  • Test changes

Test App Code Used

TypeScript AppHost

import { AzureContainerRegistryRole, createBuilder } from './.aspire/modules/aspire.mjs';

const builder = await createBuilder();

const registry = await builder.addAzureContainerRegistry('registry');
const foundry = await builder.addFoundry('foundry');
const project = foundry.addProject('project');

project.withAzureContainerRegistry(registry);
project.addContainerRegistryConnection(registry);
project.withContainerRegistryRoleAssignments(registry, [AzureContainerRegistryRole.AcrPull]);

const hostedAgent = builder
  .addDockerfile('agent-ha', './agent')
  .withHttpEndpoint({ targetPort: 8088, env: 'DEFAULT_AD_PORT' });

hostedAgent.asHostedAgent(project, {
  protocols: [{ protocol: 'invocations', version: '1.0.0' }]
});

await builder.build().runAsync();

Hosted agent container

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY main.py .
EXPOSE 8088
CMD ["python", "main.py"]
azure-ai-agentserver-invocations==1.0.0b4
from azure.ai.agentserver.invocations import AsyncAgentsApp, Request, Response, StreamingResponse

app = AsyncAgentsApp()

@app.task_route()
async def invoke(request: Request) -> Response:
    message = request.data.get("message", "")
    return Response(data={
        "protocol": "invocations",
        "scenario": "pr-17732-typescript-apphost",
        "value": f"TypeScript hosted agent processed: {message}"
    })

@app.task_route(streaming=True)
async def invoke_streaming(request: Request) -> StreamingResponse:
    async def stream():
        yield {"delta": request.data.get("message", "")}

    return StreamingResponse(data=stream())

if __name__ == "__main__":
    app.run()

Test Scenarios Executed

Scenario 1: TypeScript AppHost deploys an invocations hosted agent

Objective: Verify a TypeScript AppHost can configure a Foundry hosted agent with protocols: [{ protocol: "invocations", version: "1.0.0" }] and deploy it end to end.
Coverage Type: Happy path
Status: Passed

Steps:

  1. Installed the PR dogfood CLI and verified its version matched the PR head commit.
  2. Created a temporary TypeScript empty AppHost.
  3. Added the Foundry hosting integration from the PR package hive.
  4. Configured Azure Container Registry, Foundry, a Foundry project, a Dockerfile-backed agent container, and asHostedAgent(..., { protocols: [...] }).
  5. Deployed the TypeScript AppHost to a Foundry region that supports hosted agents.
  6. Queried the hosted agent version and endpoint metadata.
  7. Called the endpoint-scoped /protocols/invocations route.

Evidence:

  • Deployment completed successfully.
  • Latest hosted-agent version was created with container_protocol_versions=[{ protocol: "invocations", version: "1.0.0" }].
  • Endpoint metadata advertised agent_endpoint.protocols=["invocations"].
  • POST /agents/agent-ha/endpoint/protocols/invocations returned HTTP 200 with the expected test-agent response.

Scenario 2: Deploy synchronizes endpoint routing from a stale protocol state

Objective: Verify deployment updates the existing hosted-agent endpoint protocol metadata instead of only creating a version with container_protocol_versions.
Coverage Type: Regression / boundary
Status: Passed

Steps:

  1. Manually reset the hosted-agent endpoint metadata to agent_endpoint.protocols=["responses"].
  2. Updated the TypeScript AppHost Aspire SDK and Foundry integration package from the previous PR build to the current PR package build.
  3. Redeployed the same TypeScript AppHost using the current PR CLI and packages.
  4. Queried the endpoint metadata after deployment.

Expected Unhappy-Path Outcome: Deployment should recover from stale endpoint metadata by restoring the endpoint to invocations without requiring a manual Foundry PATCH.

Evidence:

  • Endpoint protocols before deploy: responses.
  • Endpoint protocols after deploy: invocations.

Scenario 3: Responses route is safely rejected for an invocations-only hosted agent

Objective: Verify the hosted agent does not accept the OpenAI responses protocol when the AppHost selected only invocations.
Coverage Type: Unhappy path
Status: Passed

Steps:

  1. After the successful TypeScript deploy, called the endpoint-scoped OpenAI responses route.
  2. Confirmed the request failed safely.

Expected Unhappy-Path Outcome: The responses route should return a non-success status for an invocations-only agent.

Evidence:

  • POST /agents/agent-ha/endpoint/protocols/openai/responses returned HTTP 400 bad_request.

Summary

Scenario Status Notes
TypeScript AppHost deploys an invocations hosted agent Passed Deployed with the PR CLI and current PR packages.
Deploy synchronizes endpoint routing from a stale protocol state Passed Endpoint changed from responses to invocations during deploy.
Responses route is safely rejected Passed Responses protocol returned HTTP 400 for the invocations-only agent.

Cleanup

  • Ran aspire destroy --apphost apphost.mts --yes --non-interactive for the temporary deployment.
  • Azure accepted the resource group deletion request. Deletion continues asynchronously on the Azure side.

Overall Result

PR VERIFIED

The TypeScript AppHost scenario validates the new polyglot protocols API, the deployed hosted-agent version configuration, endpoint protocol synchronization, and runtime behavior through the invocations endpoint.

@github-actions

Copy link
Copy Markdown
Contributor

Re-running the failed jobs in the CI workflow for this pull request because 2 jobs were identified as retry-safe transient failures in the CI run attempt.
GitHub was asked to rerun all failed jobs for that attempt, and the rerun is being tracked in the rerun attempt.
The job links below point to the failed attempt jobs that matched the retry-safe transient failure rules.

Matched test failure patterns (1 test)
  • Aspire.Cli.EndToEnd.Tests.KubernetesDeployWithMongoDBTests.DeployK8sWithMongoDB — Unable to access container registry during publish

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

Re-running the failed jobs in the CI workflow for this pull request because 1 job was identified as retry-safe transient failures in the CI run attempt.
GitHub was asked to rerun all failed jobs for that attempt, and the rerun is being tracked in the rerun attempt.
The job links below point to the failed attempt jobs that matched the retry-safe transient failure rules.

@github-actions

Copy link
Copy Markdown
Contributor

CLI E2E Tests unknown — 110 passed, 0 failed, 2 unknown (commit 138725b)

View all recordings
Status Test Recording Job Artifacts
AddPackageInteractiveWhileAppHostRunningDetached Recording #78691818407 Logs
AddPackageWhileAppHostRunningDetached Recording #78691818407 Logs
AgentCommands_AllHelpOutputs_AreCorrect Recording #78691818456 Logs
AgentInitCommand_DefaultSelection_InstallsDefaultSkills Recording #78691818456 Logs
AgentInitCommand_MigratesDeprecatedConfig Recording #78691818456 Logs
AgentInitCommand_NonInteractive_BundleOnlySkillsBeyondCliCatalog_AreInstallable Recording #78691818456 Logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp Recording #78691818366 Logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp_DevLocalhost Recording #78691818366 Logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp_Isolated Recording #78691818366 Logs
AllPublishMethodsBuildDockerImages Recording #78691818287 Logs
AspireAddAndStartWorkAgainstLegacyAppHostTs Recording #78691818422 Logs
AspireAddPackageVersionToDirectoryPackagesProps Recording #78691818511 Logs
AspireInitSingleFileAppHostRunsViaDotnetRunAppHost Recording #78691818357 Logs
AspireInitWithExistingAppHostDirRecreatesMissingNuGetConfigAndPreservesFiles Recording #78691818469 Logs
AspireInitWithSolutionFileGeneratesAppHostThatBuildsAgainstChannelHive Recording #78691818469 Logs
AspireStartUpdatesStaleTypeScriptAppHostPath Recording #78691818452 Logs
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps Recording #78691818511 Logs
AspireUpdateRemovesOrphanAppHostPackageVersionWhenSdkAlreadyCurrent Recording #78691818511 Logs
Banner_DisplayedOnFirstRun Recording #78691818497 Logs
Banner_DisplayedWithExplicitFlag Recording #78691818497 Logs
Banner_NotDisplayedWithNoLogoFlag Recording #78691818497 Logs
CertificatesClean_RemovesCertificates Recording #78691818297 Logs
CertificatesTrust_WithNoCert_CreatesAndTrustsCertificate Recording #78691818297 Logs
CertificatesTrust_WithUntrustedCert_TrustsCertificate Recording #78691818297 Logs
ConfigSetGet_CreatesNestedJsonFormat Recording #78691818315 Logs
CreateAndRunAspireStarterProject Recording #78691818358 Logs
CreateAndRunAspireStarterProjectWithBundle Recording #78691818392 Logs
CreateAndRunEmptyAppHostProject Recording #78691818320 Logs
CreateAndRunJavaEmptyAppHostProject Recording #78691818481 Logs
CreateAndRunJsReactProject Recording #78691818518 Logs
CreateAndRunPolyglotAppHostWithDevLocalhostUrls Recording #78691818358 Logs
CreateAndRunPythonReactProject Recording #78691818409 Logs
CreateAndRunTypeScriptEmptyAppHostProject Recording #78691818310 Logs
CreateAndRunTypeScriptStarterProject Recording #78691818526 Logs
CreateJavaAppHostWithViteApp Recording #78691818459 Logs
CreateTypeScriptAppHostWithViteApp_AllowsGuestAppPackageManagerToDiffer Recording #78691818380 Logs
CreateTypeScriptAppHostWithViteApp_UsesConfiguredToolchain Recording #78691818380 Logs
DashboardRunWithAgentMcpListTracesReturnsNoTraces Recording #78691818364 Logs
DashboardRunWithAgentMcpListTracesReturnsNoTraces_DevLocalhost Recording #78691818364 Logs
DashboardRunWithOtelTracesReturnsNoTraces Recording #78691818364 Logs
DashboardRunWithOtelTracesReturnsNoTraces_DevLocalhost Recording #78691818364 Logs
DeployK8sBasicApiService Recording #78691818317 Logs
DeployK8sWithExternalHelmChart Recording #78691818506 Logs
DeployK8sWithGarnet Recording #78691818496 Logs
DeployK8sWithMongoDB Recording #78691818436 Logs
DeployK8sWithMySql Recording #78691818508 Logs
DeployK8sWithPostgres Recording #78691818363 Logs
DeployK8sWithRabbitMQ Recording #78691818465 Logs
DeployK8sWithRedis Recording #78691818498 Logs
DeployK8sWithSqlServer Recording #78691818365 Logs
DeployK8sWithValkey Recording #78691818384 Logs
DeployTypeScriptAppToKubernetes Recording #78691818359 Logs
DescribeCommandResolvesReplicaNames Recording #78691818489 Logs
DescribeCommandShowsRunningResources Recording #78691818489 Logs
DetachFormatJsonProducesValidJson Recording #78691818485 Logs
DetachFormatJsonProducesValidJsonWhenRestartingExistingInstance Recording #78691818485 Logs
DoPublishAndDeployListStepsWork Recording #78691818434 Logs
DocsCommand_RendersInteractiveMarkdownFromLocalSource Recording #78691818312 Logs
DoctorCommand_DetectsDeprecatedAgentConfig Recording #78691818456 Logs
DoctorCommand_TypeScriptAppHostReportsMissingConfiguredToolchain Recording #78691818492 Logs
DoctorCommand_WithSslCertDir_ShowsTrusted Recording #78691818492 Logs
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted Recording #78691818492 Logs
GatewayWithoutExternalEndpoint_FailsPublishWithGuidance Recording #78691818507 Logs
GeneratedAspireDevScript_StartsWatchMode_WithConfiguredToolchain Recording #78691818380 Logs
GlobalMigration_HandlesCommentsAndTrailingCommas Recording #78691818315 Logs
GlobalMigration_HandlesMalformedLegacyJson Recording #78691818315 Logs
GlobalMigration_PreservesAllValueTypes Recording #78691818315 Logs
GlobalMigration_SkipsWhenNewConfigExists Recording #78691818315 Logs
GlobalSettings_MigratedFromLegacyFormat Recording #78691818315 Logs
IngressWithoutExternalEndpoint_FailsPublishWithGuidance Recording #78691818507 Logs
InitTypeScriptAppHost_AugmentsExistingViteRepoInWorkspaceSubdirectory Recording #78691818380 Logs
InteractiveCSharpInitCreatesExpectedFiles Recording #78691818260 Logs
InvalidAppHostPathWithComments_IsHealedOnRun Recording #78691818430 Logs
JavaScriptHostingApisRunFromTypeScriptAppHost Recording #78691818287 Logs
LatestCliCanStartStableChannelAppHost Recording #78691818358 Logs
LatestCliCanStartStableChannelTypeScriptAppHost Recording #78691818358 Logs
LegacySettingsMigration_AdjustsRelativeAppHostPath Recording #78691818452 Logs
LogsCommandShowsResourceLogs Recording #78691818480 Logs
OtelLogsReturnsStructuredLogsFromStarterApp Recording #78691818531 Logs
OtelLogsReturnsStructuredLogsFromStarterAppIsolated Recording #78691818531 Logs
PsCommandListsRunningAppHost Recording #78691818536 Logs
PsFormatJsonOutputsOnlyJsonToStdout Recording #78691818536 Logs
PublishJavaScriptPatternsGeneratesExpectedDockerComposeArtifacts Recording #78691818321 Logs
PublishWithConfigureEnvFileUpdatesEnvOutput Recording #78691818321 Logs
PublishWithDockerComposeServiceCallbackSucceeds Recording #78691818321 Logs
PublishWithoutOutputPathUsesAppHostDirectoryDefault Recording #78691818321 Logs
ResourceCommand_FailedExecution_DisplaysAppHostLogPathAndLogContainsEntries Recording #78691818385 Logs
ResourceCommand_SetAndDeleteParameterUpdatesDescribeOutput Recording #78691818385 Logs
RestoreGeneratesSdkFiles Recording #78691818379 Logs
RestoreGeneratesSdkFiles_WithConfiguredToolchain Recording #78691818301 Logs
RestoreRefreshesGeneratedSdkAfterAddingIntegration Recording #78691818301 Logs
RestoreSupportsConfigOnlyHelperPackageAndCrossPackageTypes Recording #78691818484 Logs
RunFromParentDirectory_UsesExistingConfigNearAppHost Recording #78691818413 Logs
RunReportsSyntaxErrorsForDotNetAppHost Recording #78691818288 Logs
RunReportsSyntaxErrorsForTypeScriptAppHost Recording #78691818288 Logs
SecretCrudOnDotNetAppHost Recording #78691818499 Logs
SecretCrudOnTypeScriptAppHost Recording #78691818538 Logs
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels Recording #78691818529 Logs
StartAndWaitForTypeScriptSqlServerAppHostWithNativeAssets Recording #78691818360 Logs
StartReportsSyntaxErrorsForDotNetAppHost Recording #78691818288 Logs
StartReportsSyntaxErrorsForTypeScriptAppHost Recording #78691818288 Logs
StopAllAppHostsFromAppHostDirectory Recording #78691818542 Logs
StopJavaPolyglotAppHostUsingApphostDirectory Recording #78691818308 Logs
StopNonInteractiveSingleAppHost Recording #78691818542 Logs
StopTypeScriptPolyglotAppHostUsingApphostDirectory Recording #78691818441 Logs
StopWithNoRunningAppHostExitsSuccessfully Recording #78691818407 Logs
TypeScriptAppHostRunDoesNotDeadlockWhenLazyOptionsInvokeAsyncCallback Recording #78691818310 Logs
UnAwaitedChainsCompileWithAutoResolvePromises Recording #78691818301 Logs
UpdateProjectChannelToStable_CSharpEmptyAppHost_PreservesAspireConfigChannel Recording #78691818435 Logs
UpdateProjectChannelToStable_CSharpSingleFileInit_PreservesAspireConfigChannel Recording #78691818435 Logs
UpdateProjectChannelToStable_TypeScriptSingleFileInit_PreservesAspireConfigChannel Recording #78691818435 Logs
UpdateProjectChannelToStable_TypeScript_PreviewsStablePackagesAndPreservesChannel Recording #78691818435 Logs

📹 Recordings uploaded automatically from CI run #26700080433

@davidfowl

Copy link
Copy Markdown
Collaborator Author

PR #17732 e2e validation: Foundry invocations hosted agents

Validated the PR dogfood build end to end for Foundry hosted agents using the invocations protocol, including the smooth local-to-remote Python uv scenario with no manual Dockerfile and no manual ACR wiring.

Build under test

  • PR: Add Foundry hosted agent protocol selection #17732
  • Expected PR head: 138725b543bf8d4ffecc17ae9638ecd28cab274d
  • Installed PR CLI: 13.4.0-pr.17732.g138725b5
  • Deployment region: Foundry hosted-agent supported Azure region
  • PII note: resource names, subscription/tenant IDs, portal links, and local temp paths are intentionally omitted.

Scenario 1: TypeScript AppHost configures an invocations hosted agent

A TypeScript AppHost configured the hosted agent with:

await hostedAgent.asHostedAgent(project, {
    protocols: [{ protocol: 'invocations', version: '1.0.0' }]
});

Result: passed. The deployed hosted-agent version had the expected container protocol configuration, and the agent endpoint metadata advertised only invocations.

Scenario 2: Endpoint protocol metadata is synchronized during deploy

A previous deploy produced a hosted-agent version with container_protocol_versions, but the endpoint metadata still advertised responses. After the PR fix, redeploying patched the agent endpoint metadata so it matched the selected protocol.

Result: passed. The endpoint changed from stale responses metadata to invocations without a manual Foundry PATCH.

Scenario 3: Minimal Python uv app, no Dockerfile, no manual ACR

Validated the requested no-Dockerfile/no-manual-ACR flow with a minimal Python app. The AppHost used the Foundry project and Python hosting integration; ACR was provisioned/used automatically by the Foundry project deployment.

import { createBuilder } from './.aspire/modules/aspire.mjs';

const builder = await createBuilder();

const foundry = await builder.addFoundry('foundry');
const project = foundry.addProject('project');

const hostedAgent = await builder
    .addPythonApp('agent-ha', './agent', 'main.py')
    .withUv()
    .withHttpEndpoint({ env: 'PORT' })
    .withExternalHttpEndpoints()
    .withHttpHealthCheck({ path: '/readiness' });

await hostedAgent.asHostedAgent(project, {
    protocols: [{ protocol: 'invocations', version: '1.0.0' }]
});

await builder.build().run();
import os

import uvicorn
from fastapi import FastAPI, Request

app = FastAPI()


@app.get('/readiness')
async def readiness() -> dict[str, str]:
    return {'status': 'ready'}


@app.post('/invocations')
async def invoke(request: Request) -> dict[str, str]:
    payload = await request.json()
    message = payload.get('message', '')
    return {
        'protocol': 'invocations',
        'scenario': 'pr-17732-typescript-uv-app',
        'value': f'TypeScript uv hosted agent processed: {message}',
    }


if __name__ == '__main__':
    port = int(os.environ.get('PORT', '8000'))
    uvicorn.run(app, host='0.0.0.0', port=port)
[project]
name = 'foundry-ts-uv-agent'
version = '0.1.0'
requires-python = '>=3.12'
dependencies = [
    'fastapi>=0.136.3',
    'uvicorn>=0.48.0',
]

Deployment result: passed. Deployment completed successfully.

Runtime metadata:

{
  "hostedAgentStatus": "active",
  "endpointProtocols": ["invocations"],
  "containerProtocolVersions": [{"protocol":"invocations","version":"1.0.0"}]
}

Runtime invocation result:

POST /agents/<agent>/endpoint/protocols/invocations?api-version=v1
HTTP 200
{
  "scenario": "pr-17732-typescript-uv-app",
  "value": "TypeScript uv hosted agent processed: hello from uv e2e"
}

Negative protocol check:

POST /agents/<agent>/endpoint/protocols/openai/responses?api-version=v1
HTTP 400
{
  "error": {
    "code": "bad_request",
    "message": "Endpoint-scoped responses require the 'responses' protocol to be declared in container_protocol_versions for agent '<agent>'. Please use version '1.0.0'. [Request ID: <redacted>]"
  }
}

Additional findings covered by the PR

  • Foundry-owned runtime environment variables (PORT, AGENT_*, FOUNDRY_*) are skipped when inherited from the target resource, so Aspire local settings do not break remote hosted-agent deployment.
  • Explicitly setting those reserved names on the hosted-agent configuration still fails fast, which avoids silently accepting a value Foundry will own remotely.
  • The Python uv sample needs the application to bind to Foundry's injected PORT; using .withHttpEndpoint({ env: 'PORT' }) keeps local and remote behavior aligned.

Cleanup

Temporary Azure resources were submitted for async deletion after validation.

Overall result

Passed. PR #17732 was validated end to end for C#/TypeScript protocol selection, endpoint protocol synchronization, invocations-only runtime behavior, and the minimal Python uv hosted-agent deployment path without manual Dockerfile or manual ACR setup.

@davidfowl
David Fowler (davidfowl) merged commit 9c260c2 into release/13.4 May 31, 2026
610 of 617 checks passed
@davidfowl
David Fowler (davidfowl) deleted the davidfowl/foundry-protocol branch May 31, 2026 03:12
@microsoft-github-policy-service microsoft-github-policy-service Bot added this to the 13.4 milestone May 31, 2026
aspire-repo-bot Bot added a commit to microsoft/aspire.dev that referenced this pull request May 31, 2026
Documents the new protocol selection feature added in microsoft/aspire#17732.
Adds a 'Select the hosted agent protocol' subsection showing how to configure
ContainerProtocolVersions (C#) and protocols (TypeScript) on AsHostedAgent/asHostedAgent.
Updates the dashboard section to reflect that the Send Message command and endpoint
URLs adapt to the selected protocol (responses vs. invocations).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@aspire-repo-bot

Copy link
Copy Markdown
Contributor

Pull request created: #1141

Generated by PR Documentation Check

@aspire-repo-bot

Copy link
Copy Markdown
Contributor

📝 Documentation has been drafted in microsoft/aspire.dev#1141 targeting release/13.4.

Updated src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-foundry/azure-ai-foundry-host.mdx to document the new hosted agent protocol selection feature:

  • Added a Select the hosted agent protocol subsection with C# and TypeScript examples showing how to configure ContainerProtocolVersions / protocols on AsHostedAgent/asHostedAgent.
  • Updated the Invoke agents from the Aspire dashboard section to reflect that the Send Message command and dashboard URLs adapt to the configured protocol (/responses or /invocations).

Note

This draft PR needs human review before merging.

Jose Perez Rodriguez (joperezr) added a commit that referenced this pull request Jun 2, 2026
The merge auto-pulled release/13.4's api/*.cs and api/*.ats.txt baselines for 56 pre-existing
packages. These baselines no longer match main's source code (e.g., Foundry's source has
[AspireExport("asHostedAgent")] from #17671 but the release baseline says "asHostedAgentExecutable",
and the release baseline still references the WithComputeEnvironment method that was renamed to
the AsHostedAgent overloads in #17732).

Per repo convention (.github/copilot-instructions.md): api files are regenerated as part of the
release process, not during individual PRs. Reverting to main's state matches what @davidfowl's
forward-port PR #17775 does, and lets the next release run regenerate them.

The 2 net-new api files for the new Aspire.Hosting.Blazor and Aspire.Hosting.Go integrations
are kept as-is (they didn't exist on main).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
pull Bot pushed a commit to tooniez/aspire that referenced this pull request Jun 2, 2026
Brings 43 release-branch commits forward onto main now that 13.4.0 has shipped.
This PR replaces the original automated merge (microsoft#17804) which had to be closed so
that conflict resolution and post-merge cleanups could be made on a non-protected
branch.

Conflict resolution summary (33 files):

* Equivalent backports (took main's commit identity): ChannelUpdateWorkflowTests,
  LoggingHelpersTests, the four extension test files, AspireEditorCommandProvider,
  appHostDiscovery.

* Release-only forwards (preserved): microsoft#17732 / microsoft#17756 Foundry hosted-agent protocol
  selection and cross-compute-environment endpoint references, microsoft#17573 stabilize
  PrebuiltAppHostServer staging globalPackagesFolder path, microsoft#17743 staging-identity
  CLI darc feed routing.

* Main-only forwards (preserved): microsoft#17506 Show discovered AppHosts in Aspire pane,
  microsoft#17547 Localize Aspire skills metadata errors, microsoft#17801 VS Code v1.12.0, microsoft#17297
  Aspire CLI npm package release integration, microsoft#17576 TerminalRun IAsyncDisposable,
  microsoft#17721 / microsoft#17723 VS Code telemetry, microsoft#17671 ATS baseline fix (re-applied manually
  on top of Foundry source taken from release).

* Hybrid (manually spliced): docs/contributing.md - kept main's restructured
  layout and inserted release's staging-validation paragraph; HostedAgentBuilder-
  Extension - took release base then re-applied microsoft#17671 asHostedAgent rename;
  UpdateCommandTests - took main and injected microsoft#17743's
  OverrideCliInformationalVersionConfigKey block.

Post-merge cleanups included in this PR:

* eng/Versions.props: revert StabilizePackageVersion to false (was flipped to
  true on release/13.4 by microsoft#17520 for shipping 13.4.0; main must stay in preview
  mode).

* .github/workflows/generate-api-diffs.yml: retarget back to main (was pointed
  at release/13.4 by microsoft#17696 release prep).

* .github/workflows/backmerge-release.yml: update from release/13.3 to
  release/13.4 (was stale - missed the 13.4 release-time bump).

* .github/workflows/milestone-assignment.yml: audited - already correct
  (main -> 13.5, release/13.4 -> 13.4.x); no change.

This merge commit must be preserved - do not squash on merge.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 30, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants