diff --git a/src/frontend/scripts/generate-twoslash-types.ts b/src/frontend/scripts/generate-twoslash-types.ts index 3fa817e29..49769189f 100644 --- a/src/frontend/scripts/generate-twoslash-types.ts +++ b/src/frontend/scripts/generate-twoslash-types.ts @@ -43,6 +43,8 @@ interface FunctionEntry { interface DtoField { name: string; type: string; + isOptional?: boolean; + isNullable?: boolean; } interface DtoType { @@ -690,9 +692,11 @@ for (const dto of dtoTypes) { parts.push(`export interface ${dto.name} {`); for (const f of dto.fields) { const t = cleanType(f.type); + const optional = f.isOptional ? '?' : ''; + const nullable = f.isNullable ? ' | null' : ''; extractTypeIdentifiers(t, referencedTypes); scanExprForGenerics(t); - parts.push(` ${camelCase(f.name)}: ${t};`); + parts.push(` ${camelCase(f.name)}${optional}: ${t}${nullable};`); } parts.push(`}`); parts.push(''); diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-foundry/azure-ai-foundry-host.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-foundry/azure-ai-foundry-host.mdx index e2bcff7eb..6c73c33ab 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-foundry/azure-ai-foundry-host.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-foundry/azure-ai-foundry-host.mdx @@ -30,8 +30,8 @@ If you're new to the Azure AI Foundry integration, start with the [Get started w To start building an Aspire app that uses Azure AI Foundry, install the [📦 Aspire.Hosting.Foundry](https://www.nuget.org/packages/Aspire.Hosting.Foundry) NuGet package: - - + + ```bash title="Terminal" aspire add azure-ai-foundry @@ -61,7 +61,7 @@ Or, choose a manual installation approach: - + ```bash title="Terminal" aspire add azure-ai-foundry @@ -464,6 +464,72 @@ In publish mode, Aspire creates an `AzureHostedAgentResource` and publishes the For C# AppHosts, the parameterless `AsHostedAgent()` overload reuses an existing Foundry project from the app model or creates one automatically. TypeScript AppHosts pass the project resource explicitly. +### Select the hosted agent protocol + +By default, Aspire configures a hosted agent for the `responses` protocol. If your agent implements the `invocations` protocol, configure the protocol versions when configuring the hosted agent in your AppHost. The selected protocol affects both run mode (dashboard URLs and the **Send Message** command) and publish mode (the `container_protocol_versions` field in the Foundry hosted agent definition). + + + + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var foundry = builder.AddFoundry("foundry"); +var project = foundry.AddProject("my-project"); +var chat = project.AddModelDeployment("chat", FoundryModel.OpenAI.Gpt5Mini); + +builder.AddProject("agent-dotnet") + .WithReference(project) + .WithReference(chat) + .AsHostedAgent(project, configuration => + { + configuration.ContainerProtocolVersions.Clear(); + configuration.ContainerProtocolVersions.Add( + new ProtocolVersionRecord(ProjectsAgentProtocol.Invocations, "1.0.0")); + }); + +builder.Build().Run(); +``` + + + + +```typescript title="TypeScript — apphost.mts" twoslash +import { createBuilder } from './.aspire/modules/aspire.mjs'; + +const builder = await createBuilder(); + +const foundry = await builder.addFoundry('foundry'); +const project = await foundry.addProject('my-project'); +const chat = await project.addModelDeployment('chat', { + name: 'gpt-5-mini', + version: '2025-06-01', + format: 'OpenAI', +}); + +const agent = await builder + .addProject('agent-dotnet', '../Agent/Agent.csproj') + .withReference(project) + .withReference(chat); + +await agent.asHostedAgent(project, { + protocols: [{ protocol: 'invocations', version: '1.0.0' }], +}); + +await builder.build().run(); +``` + + + + +When the first configured protocol version uses the `invocations` protocol, Aspire: + +- Labels the run-mode dashboard endpoint as **Invocations Endpoint** and routes dashboard URLs to `/invocations` instead of `/responses`. +- Configures the **Send Message** dashboard command to POST to `/invocations`. +- Emits the selected protocol versions in the `container_protocol_versions` field of the Foundry hosted agent definition at publish time. + +Multiple protocol versions can be listed. In run mode only the first entry is used to select the endpoint path; in publish mode all entries are forwarded to the hosted agent definition. + ### Add and publish a prompt agent For prompt-only scenarios, use `AddPromptAgent` on a Foundry project: @@ -539,7 +605,7 @@ Prompt agents are deployed to Azure AI Foundry even during local development. Lo ## Invoke agents from the Aspire dashboard -Aspire also makes the declared agents easy to try from the dashboard. Prompt agents get a **Send Message** command from `AddPromptAgent(...)`. Hosted agents configured with `AsHostedAgent(...)` get a highlighted **Send Message** command that posts to the selected protocol path, which defaults to the local `/responses` endpoint. +Aspire also makes the declared agents easy to try from the dashboard. Prompt agents get a **Send Message** command from `AddPromptAgent(...)`. Hosted agents configured with `AsHostedAgent(...)` get a highlighted **Send Message** command that posts to the selected protocol path (`/responses` by default, or `/invocations` when the invocations protocol is configured), plus dashboard links for the protocol endpoint, `/liveness`, and `/readiness`. Promise): IResourceWithEndpoints", + "parameters": [ + { + "name": "project", + "type": "AzureCognitiveServicesProjectResource", + "isOptional": true + }, + { + "name": "configure", + "type": "callback", + "isOptional": true, + "isCallback": true, + "callbackSignature": "(obj: HostedAgentConfiguration) => Promise" + } + ], + "returnType": "IResourceWithEndpoints", + "returnsBuilder": true, + "targetTypeId": "Aspire.Hosting/Aspire.Hosting.ApplicationModel.IResourceWithEndpoints", + "expandedTargetTypes": [ + "Aspire.Hosting.ApplicationModel.ContainerResource", + "Aspire.Hosting.ApplicationModel.ExecutableResource", + "Aspire.Hosting.ApplicationModel.ProjectResource", + "Aspire.Hosting.ApplicationModel.DotnetToolResource", + "Aspire.Hosting.ApplicationModel.CSharpAppResource", + "Aspire.Hosting.Foundry.FoundryResource", + "Aspire.Hosting.AzureCosmosDBResource", + "Aspire.Hosting.Azure.AzureStorageResource", + "Aspire.Hosting.Azure.AzureKeyVaultResource", + "Aspire.Hosting.Azure.AzureCosmosDBEmulatorResource", + "Aspire.Hosting.Azure.AzureStorageEmulatorResource" + ] + }, { "name": "withFoundryRoleAssignments", "capabilityId": "Aspire.Hosting.Foundry/withFoundryRoleAssignments", @@ -3089,6 +3128,69 @@ } ], "dtoTypes": [ + { + "name": "HostedAgentOptions", + "fullName": "Aspire.Hosting.Foundry.HostedAgentOptions", + "kind": "dto", + "description": "Optional hosted agent deployment options.", + "fields": [ + { + "name": "Description", + "type": "string", + "isOptional": true, + "isNullable": true, + "description": "The description of the hosted agent." + }, + { + "name": "EnvironmentVariables", + "type": "Dict", + "isOptional": true, + "description": "Environment variables to set on the hosted agent resource." + }, + { + "name": "Cpu", + "type": "number", + "isOptional": true, + "description": "CPU allocation for each hosted agent instance, in vCPU cores." + }, + { + "name": "Memory", + "type": "number", + "isOptional": true, + "description": "Memory allocation for each hosted agent instance, in GiB. Must be 2x the CPU allocation." + }, + { + "name": "Metadata", + "type": "Dict", + "isOptional": true, + "description": "Additional metadata to associate with the hosted agent." + }, + { + "name": "Protocols", + "type": "HostedAgentProtocolVersion[]", + "isOptional": true, + "description": "The hosted agent protocol versions." + } + ] + }, + { + "name": "HostedAgentProtocolVersion", + "fullName": "Aspire.Hosting.Foundry.HostedAgentProtocolVersion", + "kind": "dto", + "description": "A protocol and version supported by a Microsoft Foundry hosted agent container.", + "fields": [ + { + "name": "Protocol", + "type": "string", + "description": "The protocol name, such as responses or invocations." + }, + { + "name": "Version", + "type": "string", + "description": "The protocol version, such as 1.0.0." + } + ] + }, { "name": "FoundryModel", "fullName": "Aspire.Hosting.Foundry.FoundryModel", diff --git a/src/frontend/src/data/twoslash/aspire.d.ts b/src/frontend/src/data/twoslash/aspire.d.ts index 3361ad54d..22e81582f 100644 --- a/src/frontend/src/data/twoslash/aspire.d.ts +++ b/src/frontend/src/data/twoslash/aspire.d.ts @@ -534,7 +534,7 @@ export interface CertificateTrustExecutionConfigurationContext { certificateBundlePath: ReferenceExpression; certificateDirectoriesPath: ReferenceExpression; rootCertificatesPath: string; - isContainer: boolean; + isContainer?: boolean; } /** @@ -549,7 +549,7 @@ export interface CommandOptions { visibility: ResourceCommandVisibility; confirmationMessage: string; iconName: string; - iconVariant: IconVariant; + iconVariant?: IconVariant; isHighlighted: boolean; updateState: callback; } @@ -560,8 +560,8 @@ export interface CommandOptions { export interface CommandResultData { value: string; - format: CommandResultFormat; - displayImmediately: boolean; + format?: CommandResultFormat; + displayImmediately?: boolean; } /** @@ -570,10 +570,10 @@ export interface CommandResultData { export interface ExecuteCommandResult { success: boolean; - canceled: boolean; - errorMessage: string; - message: string; - data: CommandResultData; + canceled?: boolean; + errorMessage?: string; + message?: string; + data?: CommandResultData; } /** @@ -600,7 +600,7 @@ export interface HttpCommandExportOptions { description: string; confirmationMessage: string; iconName: string; - iconVariant: IconVariant; + iconVariant?: IconVariant; isHighlighted: boolean; commandName: string; endpointName: string; @@ -627,12 +627,12 @@ export interface ProcessCommandExportOptions { arguments: string[]; workingDirectory: string; environmentVariables: Dict; - inheritEnvironmentVariables: boolean; + inheritEnvironmentVariables?: boolean; standardInputContent: string; - killEntireProcessTree: boolean; + killEntireProcessTree?: boolean; commandOptions: CommandOptions; - maxOutputLineCount: number; - displayImmediately: boolean; + maxOutputLineCount?: number; + displayImmediately?: boolean; successExitCodes: number[]; } @@ -642,8 +642,8 @@ export interface ProcessCommandExportOptions { export interface ProcessCommandResultExportOptions { commandOptions: CommandOptions; - maxOutputLineCount: number; - displayImmediately: boolean; + maxOutputLineCount?: number; + displayImmediately?: boolean; successExitCodes: number[]; } @@ -656,9 +656,9 @@ export interface ProcessCommandSpecExportData { arguments: string[]; workingDirectory: string; environmentVariables: Dict; - inheritEnvironmentVariables: boolean; + inheritEnvironmentVariables?: boolean; standardInputContent: string; - killEntireProcessTree: boolean; + killEntireProcessTree?: boolean; } /** @@ -668,7 +668,7 @@ export interface ProcessCommandSpecExportData { export interface ResourceUrlAnnotation { url: string; displayText: string; - endpoint: EndpointReference; + endpoint?: EndpointReference; displayLocation: UrlDisplayLocation; } @@ -678,10 +678,10 @@ export interface ResourceUrlAnnotation { export interface UpdateCommandStateResourceSnapshot { resourceType: string; - state: string; - stateStyle: string; - healthStatus: HealthStatus; - exitCode: number; + state?: string; + stateStyle?: string; + healthStatus?: HealthStatus; + exitCode?: number; } /** @@ -690,7 +690,7 @@ export interface UpdateCommandStateResourceSnapshot { export interface AddContainerOptions { image: string; - tag: string; + tag?: string; } /** @@ -724,12 +724,12 @@ export interface CreateBuilderOptions { export interface HttpsCertificateExecutionConfigurationExportData { subject: string; - thumbprint: string; + thumbprint?: string; keyPathExpression: string; pfxPathExpression: string; isKeyPathReferenced: boolean; isPfxPathReferenced: boolean; - password: string; + password?: string; } /** @@ -739,7 +739,7 @@ export interface HttpsCertificateExecutionConfigurationExportData { export interface HttpsCertificateInfo { subject: string; issuer: string; - thumbprint: string; + thumbprint?: string; } /** @@ -760,10 +760,10 @@ export interface ReferenceEnvironmentInjectionOptions { export interface ResourceEventDto { resourceName: string; resourceId: string; - state: string; - stateStyle: string; - healthStatus: string; - exitCode: number; + state?: string; + stateStyle?: string; + healthStatus?: string; + exitCode?: number; } /** @@ -772,18 +772,18 @@ export interface ResourceEventDto { export interface InteractionInput { name: string; - label: string; - description: string; - enableDescriptionMarkdown: boolean; + label?: string; + description?: string; + enableDescriptionMarkdown?: boolean; inputType: InputType; - required: boolean; + required?: boolean; options: String[]; - dynamicLoading: InputLoadOptions; + dynamicLoading?: InputLoadOptions; value: string; - placeholder: string; - allowCustomChoice: boolean; + placeholder?: string; + allowCustomChoice?: boolean; disabled: boolean; - maxLength: number; + maxLength?: number; } /** @@ -791,7 +791,7 @@ export interface InteractionInput { */ export interface AzureContainerAppScaleConfig { - minReplicas: number; + minReplicas?: number; } /** @@ -799,7 +799,7 @@ export interface AzureContainerAppScaleConfig { */ export interface AzureAppServiceSiteConfig { - isAlwaysOn: boolean; + isAlwaysOn?: boolean; } /** @@ -809,12 +809,12 @@ export interface AzureAppServiceSiteConfig { export interface AzureNspAccessRule { name: string; direction: NetworkSecurityPerimeterAccessRuleDirection; - addressPrefixes: List; - addressPrefixReferences: List; - subscriptions: List; - subscriptionReferences: List; - fullyQualifiedDomainNames: List; - fullyQualifiedDomainNameReferences: List; + addressPrefixes?: List; + addressPrefixReferences?: List; + subscriptions?: List; + subscriptionReferences?: List; + fullyQualifiedDomainNames?: List; + fullyQualifiedDomainNameReferences?: List; } /** @@ -850,7 +850,7 @@ export interface AzureServiceBusCorrelationFilter { sessionId: string; replyToSessionId: string; contentType: string; - requiresPreprocessing: boolean; + requiresPreprocessing?: boolean; } /** @@ -863,6 +863,28 @@ export interface AzureServiceBusRule { filterType: AzureServiceBusFilterType; } +/** + * DTO Aspire.Hosting.Foundry.HostedAgentOptions + */ + +export interface HostedAgentOptions { + description?: string | null; + environmentVariables?: Dict; + cpu?: number; + memory?: number; + metadata?: Dict; + protocols?: HostedAgentProtocolVersion[]; +} + +/** + * DTO Aspire.Hosting.Foundry.HostedAgentProtocolVersion + */ + +export interface HostedAgentProtocolVersion { + protocol: string; + version: string; +} + /** * DTO Aspire.Hosting.Foundry.FoundryModel */ @@ -900,12 +922,12 @@ export interface HostedAgentProtocolVersion { */ export interface YarpActiveHealthCheckConfig { - enabled: boolean; - interval: timespan; + enabled?: boolean; + interval?: timespan; path: string; policy: string; query: string; - timeout: timespan; + timeout?: timespan; } /** @@ -913,10 +935,10 @@ export interface YarpActiveHealthCheckConfig { */ export interface YarpForwarderRequestConfig { - activityTimeout: timespan; - allowResponseBuffering: boolean; + activityTimeout?: timespan; + allowResponseBuffering?: boolean; version: string; - versionPolicy: HttpVersionPolicy; + versionPolicy?: HttpVersionPolicy; } /** @@ -934,9 +956,9 @@ export interface YarpHealthCheckConfig { */ export interface YarpHttpClientConfig { - dangerousAcceptAnyServerCertificate: boolean; - enableMultipleHttp2Connections: boolean; - maxConnectionsPerServer: number; + dangerousAcceptAnyServerCertificate?: boolean; + enableMultipleHttp2Connections?: boolean; + maxConnectionsPerServer?: number; requestHeaderEncoding: string; responseHeaderEncoding: string; sslProtocols: YarpSslProtocol[]; @@ -948,9 +970,9 @@ export interface YarpHttpClientConfig { */ export interface YarpPassiveHealthCheckConfig { - enabled: boolean; + enabled?: boolean; policy: string; - reactivationPeriod: timespan; + reactivationPeriod?: timespan; } /** @@ -994,7 +1016,7 @@ export interface YarpRouteQueryParameterMatch { export interface YarpSessionAffinityConfig { affinityKeyName: string; cookie: YarpSessionAffinityCookieConfig; - enabled: boolean; + enabled?: boolean; failurePolicy: string; policy: string; } @@ -1005,13 +1027,13 @@ export interface YarpSessionAffinityConfig { export interface YarpSessionAffinityCookieConfig { domain: string; - expiration: timespan; - httpOnly: boolean; - isEssential: boolean; - maxAge: timespan; + expiration?: timespan; + httpOnly?: boolean; + isEssential?: boolean; + maxAge?: timespan; path: string; - sameSite: SameSiteMode; - securePolicy: CookieSecurePolicy; + sameSite?: SameSiteMode; + securePolicy?: CookieSecurePolicy; } /** @@ -1020,8 +1042,8 @@ export interface YarpSessionAffinityCookieConfig { export interface YarpWebProxyConfig { address: uri; - bypassOnLocal: boolean; - useDefaultCredentials: boolean; + bypassOnLocal?: boolean; + useDefaultCredentials?: boolean; } // ---- handle types ---- @@ -15263,6 +15285,11 @@ export interface ContainerResource { */ asHostedAgent(project: AzureCognitiveServicesProjectResource, options?: HostedAgentOptions): IResourceWithEndpoints; + /** + * Configures the resource to run and publish as a hosted agent in Microsoft Foundry, targeting the specified Foundry project. + */ + + asHostedAgent(project: AzureCognitiveServicesProjectResource, options?: HostedAgentOptions): IComputeResource; /** * Assigns the specified roles to the given resource, granting it the necessary permissions on the target Microsoft Foundry resource. This replaces the default role assignments for the resource. */ @@ -15927,6 +15954,11 @@ export interface CSharpAppResource { */ asHostedAgent(project: AzureCognitiveServicesProjectResource, options?: HostedAgentOptions): IResourceWithEndpoints; + /** + * Configures the resource to run and publish as a hosted agent in Microsoft Foundry, targeting the specified Foundry project. + */ + + asHostedAgent(project: AzureCognitiveServicesProjectResource, options?: HostedAgentOptions): IComputeResource; /** * Assigns the specified roles to the given resource, granting it the necessary permissions on the target Microsoft Foundry resource. This replaces the default role assignments for the resource. */ @@ -16570,6 +16602,11 @@ export interface DotnetToolResource { */ asHostedAgent(project: AzureCognitiveServicesProjectResource, options?: HostedAgentOptions): IResourceWithEndpoints; + /** + * Configures the resource to run and publish as a hosted agent in Microsoft Foundry, targeting the specified Foundry project. + */ + + asHostedAgent(project: AzureCognitiveServicesProjectResource, options?: HostedAgentOptions): IComputeResource; /** * Assigns the specified roles to the given resource, granting it the necessary permissions on the target Microsoft Foundry resource. This replaces the default role assignments for the resource. */ @@ -17202,6 +17239,11 @@ export interface ExecutableResource { */ asHostedAgent(project: AzureCognitiveServicesProjectResource, options?: HostedAgentOptions): IResourceWithEndpoints; + /** + * Configures the resource to run and publish as a hosted agent in Microsoft Foundry, targeting the specified Foundry project. + */ + + asHostedAgent(project: AzureCognitiveServicesProjectResource, options?: HostedAgentOptions): IComputeResource; /** * Assigns the specified roles to the given resource, granting it the necessary permissions on the target Microsoft Foundry resource. This replaces the default role assignments for the resource. */ @@ -17671,6 +17713,11 @@ export interface IComputeResource { */ publishAsDockerComposeService(configure: (arg1: DockerComposeServiceResource, arg2: Service) => Promise): this; + /** + * Configures the resource to run and publish as a hosted agent in Microsoft Foundry, targeting the specified Foundry project. + */ + + asHostedAgent(project: AzureCognitiveServicesProjectResource, options?: HostedAgentOptions): IComputeResource; /** * Publishes the specified resource as a Kubernetes service. */ @@ -19326,6 +19373,11 @@ export interface ProjectResource { */ asHostedAgent(project: AzureCognitiveServicesProjectResource, options?: HostedAgentOptions): IResourceWithEndpoints; + /** + * Configures the resource to run and publish as a hosted agent in Microsoft Foundry, targeting the specified Foundry project. + */ + + asHostedAgent(project: AzureCognitiveServicesProjectResource, options?: HostedAgentOptions): IComputeResource; /** * Assigns the specified roles to the given resource, granting it the necessary permissions on the target Microsoft Foundry resource. This replaces the default role assignments for the resource. */