Skip to content

Commit d14ecbe

Browse files
authored
[Agents Extension] Post deploy print update (#7974)
* Update end of deploy handling to print the urls which a user would invoke Signed-off-by: trangevi <trangevi@microsoft.com> * Pr comments Signed-off-by: trangevi <trangevi@microsoft.com> --------- Signed-off-by: trangevi <trangevi@microsoft.com>
1 parent 991b974 commit d14ecbe

2 files changed

Lines changed: 407 additions & 38 deletions

File tree

cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go

Lines changed: 135 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,23 @@ import (
3030

3131
// Reference implementation
3232

33+
// agentAPIVersion is the API version used for agent endpoint invocation URLs.
34+
const agentAPIVersion = "2025-11-15-preview"
35+
36+
// displayableProtocolEntry defines a protocol that produces user-visible invocation endpoints.
37+
type displayableProtocolEntry struct {
38+
Protocol agent_api.AgentProtocol
39+
URLPath string // path suffix in the invocation URL
40+
EnvSuffix string // suffix used in AGENT_{KEY}_{SUFFIX}_ENDPOINT env vars
41+
}
42+
43+
// displayableProtocols is the single source of truth for protocols that produce
44+
// user-facing invocation endpoints and env vars.
45+
var displayableProtocols = []displayableProtocolEntry{
46+
{Protocol: agent_api.AgentProtocolResponses, URLPath: "openai/responses", EnvSuffix: "RESPONSES"},
47+
{Protocol: agent_api.AgentProtocolInvocations, URLPath: "invocations", EnvSuffix: "INVOCATIONS"},
48+
}
49+
3350
// Ensure AgentServiceTargetProvider implements ServiceTargetProvider interface
3451
var _ azdext.ServiceTargetProvider = &AgentServiceTargetProvider{}
3552

@@ -231,9 +248,24 @@ func (p *AgentServiceTargetProvider) Endpoints(
231248
)
232249
}
233250

234-
endpoint := p.agentEndpoint(azdEnv["AZURE_AI_PROJECT_ENDPOINT"], azdEnv[agentNameKey], azdEnv[agentVersionKey])
251+
// Collect per-protocol endpoint env vars
252+
var endpoints []string
253+
for _, dp := range displayableProtocols {
254+
key := fmt.Sprintf("AGENT_%s_%s_ENDPOINT", serviceKey, dp.EnvSuffix)
255+
if val := azdEnv[key]; val != "" {
256+
endpoints = append(endpoints, val)
257+
}
258+
}
259+
260+
if len(endpoints) == 0 {
261+
return nil, exterrors.Dependency(
262+
exterrors.CodeMissingAgentEnvVars,
263+
fmt.Sprintf("no agent endpoint variables found for service %s", serviceKey),
264+
"run 'azd deploy' to deploy the agent and set these variables",
265+
)
266+
}
235267

236-
return []string{endpoint}, nil
268+
return endpoints, nil
237269
}
238270

239271
// GetTargetResource returns a custom target resource for the agent service
@@ -566,8 +598,11 @@ func (p *AgentServiceTargetProvider) deployPromptAgent(
566598
return nil, err
567599
}
568600

569-
// Register agent info in environment
570-
err = p.registerAgentEnvironmentVariables(ctx, azdEnv, serviceConfig, agentVersionResponse)
601+
// Register agent info in environment (prompt agents use the responses protocol)
602+
promptProtocols := []agent_yaml.ProtocolVersionRecord{
603+
{Protocol: string(agent_api.AgentProtocolResponses), Version: "1.0.0"},
604+
}
605+
err = p.registerAgentEnvironmentVariables(ctx, azdEnv, serviceConfig, agentVersionResponse, promptProtocols)
571606
if err != nil {
572607
return nil, err
573608
}
@@ -579,14 +614,15 @@ func (p *AgentServiceTargetProvider) deployPromptAgent(
579614
agentVersionResponse.Version,
580615
azdEnv["AZURE_AI_PROJECT_ID"],
581616
azdEnv["AZURE_AI_PROJECT_ENDPOINT"],
617+
promptProtocols,
582618
)
583619

584620
return &azdext.ServiceDeployResult{
585621
Artifacts: artifacts,
586622
}, nil
587623
}
588624

589-
// deployHostedAgent handles deployment of hosted container agents
625+
// deployHostedAgent deploys a container-based hosted agent to the Foundry service.
590626
func (p *AgentServiceTargetProvider) deployHostedAgent(
591627
ctx context.Context,
592628
serviceConfig *azdext.ServiceConfig,
@@ -691,7 +727,16 @@ func (p *AgentServiceTargetProvider) deployHostedAgent(
691727

692728
// Register agent info in environment
693729
progress("Registering agent environment variables")
694-
err = p.registerAgentEnvironmentVariables(ctx, azdEnv, serviceConfig, agentVersionResponse)
730+
731+
// Default to "responses" protocol when none specified in agent.yaml.
732+
protocols := agentDef.Protocols
733+
if len(protocols) == 0 {
734+
protocols = []agent_yaml.ProtocolVersionRecord{
735+
{Protocol: string(agent_api.AgentProtocolResponses), Version: "1.0.0"},
736+
}
737+
}
738+
739+
err = p.registerAgentEnvironmentVariables(ctx, azdEnv, serviceConfig, agentVersionResponse, protocols)
695740
if err != nil {
696741
return nil, err
697742
}
@@ -701,19 +746,22 @@ func (p *AgentServiceTargetProvider) deployHostedAgent(
701746
agentVersionResponse.Version,
702747
azdEnv["AZURE_AI_PROJECT_ID"],
703748
azdEnv["AZURE_AI_PROJECT_ENDPOINT"],
749+
protocols,
704750
)
705751

706752
return &azdext.ServiceDeployResult{
707753
Artifacts: artifacts,
708754
}, nil
709755
}
710756

711-
// deployArtifacts constructs the artifacts list for deployment results
757+
// deployArtifacts constructs the artifacts list for deployment results.
758+
// It produces one endpoint artifact per displayable protocol.
712759
func (p *AgentServiceTargetProvider) deployArtifacts(
713760
agentName string,
714761
agentVersion string,
715762
projectResourceID string,
716763
projectEndpoint string,
764+
protocols []agent_yaml.ProtocolVersionRecord,
717765
) []*azdext.Artifact {
718766
artifacts := []*azdext.Artifact{}
719767

@@ -734,30 +782,72 @@ func (p *AgentServiceTargetProvider) deployArtifacts(
734782
}
735783
}
736784

737-
// Add agent endpoint
785+
// Add agent endpoint(s) — one per displayable protocol
738786
if projectEndpoint != "" {
739-
agentEndpoint := p.agentEndpoint(projectEndpoint, agentName, agentVersion)
740-
artifacts = append(artifacts, &azdext.Artifact{
741-
Kind: azdext.ArtifactKind_ARTIFACT_KIND_ENDPOINT,
742-
Location: agentEndpoint,
743-
LocationKind: azdext.LocationKind_LOCATION_KIND_REMOTE,
744-
Metadata: map[string]string{
745-
"agentName": agentName,
746-
"agentVersion": agentVersion,
747-
"label": "Agent endpoint",
748-
"clickable": "false",
749-
"note": "For information on invoking the agent, see " + output.WithLinkFormat(
750-
"https://aka.ms/azd-agents-invoke"),
751-
},
752-
})
787+
endpoints := agentInvocationEndpoints(projectEndpoint, agentName, protocols)
788+
for _, ep := range endpoints {
789+
artifacts = append(artifacts, &azdext.Artifact{
790+
Kind: azdext.ArtifactKind_ARTIFACT_KIND_ENDPOINT,
791+
Location: ep.URL,
792+
LocationKind: azdext.LocationKind_LOCATION_KIND_REMOTE,
793+
Metadata: map[string]string{
794+
"agentName": agentName,
795+
"agentVersion": agentVersion,
796+
"label": fmt.Sprintf("Agent endpoint (%s)", ep.Protocol),
797+
"clickable": "false",
798+
},
799+
})
800+
}
801+
802+
// Attach the informational note to the last endpoint only, to avoid repetition.
803+
if len(endpoints) > 0 {
804+
last := artifacts[len(artifacts)-1]
805+
last.Metadata["note"] = "For information on invoking the agent, see " + output.WithLinkFormat(
806+
"https://aka.ms/azd-agents-invoke")
807+
}
753808
}
754809

755810
return artifacts
756811
}
757812

758-
// agentEndpoint constructs the agent endpoint URL from the provided parameters
759-
func (p *AgentServiceTargetProvider) agentEndpoint(projectEndpoint, agentName, agentVersion string) string {
760-
return fmt.Sprintf("%s/agents/%s/versions/%s", projectEndpoint, agentName, agentVersion)
813+
// protocolEndpointInfo holds a displayable protocol label and its invocation URL.
814+
type protocolEndpointInfo struct {
815+
Protocol string
816+
URL string
817+
}
818+
819+
// protocolPath maps an agent protocol to its URL path suffix.
820+
// Returns empty string for protocols that should not be displayed.
821+
func protocolPath(protocol string) string {
822+
for _, dp := range displayableProtocols {
823+
if agent_api.AgentProtocol(protocol) == dp.Protocol {
824+
return dp.URLPath
825+
}
826+
}
827+
return ""
828+
}
829+
830+
// agentInvocationEndpoints builds the list of displayable invocation endpoints
831+
// from the agent's protocols.
832+
func agentInvocationEndpoints(
833+
projectEndpoint string,
834+
agentName string,
835+
protocols []agent_yaml.ProtocolVersionRecord,
836+
) []protocolEndpointInfo {
837+
var endpoints []protocolEndpointInfo
838+
for _, p := range protocols {
839+
path := protocolPath(p.Protocol)
840+
if path == "" {
841+
continue
842+
}
843+
endpoints = append(endpoints, protocolEndpointInfo{
844+
Protocol: p.Protocol,
845+
URL: fmt.Sprintf(
846+
"%s/agents/%s/endpoint/protocols/%s?api-version=%s",
847+
projectEndpoint, agentName, path, agentAPIVersion),
848+
})
849+
}
850+
return endpoints
761851
}
762852

763853
// agentPlaygroundUrl constructs a URL to the agent playground in the Foundry portal
@@ -800,9 +890,6 @@ func (p *AgentServiceTargetProvider) createAgent(
800890
p.credential,
801891
)
802892

803-
// Use constant API version
804-
const apiVersion = "2025-11-15-preview"
805-
806893
// Extract CreateAgentVersionRequest from CreateAgentRequest
807894
versionRequest := &agent_api.CreateAgentVersionRequest{
808895
Description: request.Description,
@@ -811,7 +898,7 @@ func (p *AgentServiceTargetProvider) createAgent(
811898
}
812899

813900
// Create agent version
814-
agentVersionResponse, err := agentClient.CreateAgentVersion(ctx, request.Name, versionRequest, apiVersion)
901+
agentVersionResponse, err := agentClient.CreateAgentVersion(ctx, request.Name, versionRequest, agentAPIVersion)
815902
if err != nil {
816903
return nil, exterrors.ServiceFromAzure(err, exterrors.OpCreateAgent)
817904
}
@@ -855,25 +942,35 @@ func (p *AgentServiceTargetProvider) displayAgentInfo(request *agent_api.CreateA
855942
fmt.Fprintln(os.Stderr)
856943
}
857944

858-
// registerAgentEnvironmentVariables registers agent information as azd environment variables
945+
// registerAgentEnvironmentVariables registers agent information as azd environment variables.
946+
// Per-protocol endpoint vars are set (e.g. AGENT_{KEY}_RESPONSES_ENDPOINT).
947+
// The legacy single-endpoint var (AGENT_{KEY}_ENDPOINT) is cleared to avoid stale data.
859948
func (p *AgentServiceTargetProvider) registerAgentEnvironmentVariables(
860949
ctx context.Context,
861950
azdEnv map[string]string,
862951
serviceConfig *azdext.ServiceConfig,
863952
agentVersionResponse *agent_api.AgentVersionObject,
953+
protocols []agent_yaml.ProtocolVersionRecord,
864954
) error {
955+
serviceKey := p.getServiceKey(serviceConfig.Name)
956+
envVars := map[string]string{
957+
fmt.Sprintf("AGENT_%s_NAME", serviceKey): agentVersionResponse.Name,
958+
fmt.Sprintf("AGENT_%s_VERSION", serviceKey): agentVersionResponse.Version,
959+
}
960+
961+
// Clear legacy single-endpoint var so upgraded environments don't retain stale URLs.
962+
legacyKey := fmt.Sprintf("AGENT_%s_ENDPOINT", serviceKey)
963+
envVars[legacyKey] = ""
865964

866-
endpoint := p.agentEndpoint(
965+
endpoints := agentInvocationEndpoints(
867966
azdEnv["AZURE_AI_PROJECT_ENDPOINT"],
868967
agentVersionResponse.Name,
869-
agentVersionResponse.Version,
968+
protocols,
870969
)
871-
872-
serviceKey := p.getServiceKey(serviceConfig.Name)
873-
envVars := map[string]string{
874-
fmt.Sprintf("AGENT_%s_NAME", serviceKey): agentVersionResponse.Name,
875-
fmt.Sprintf("AGENT_%s_VERSION", serviceKey): agentVersionResponse.Version,
876-
fmt.Sprintf("AGENT_%s_ENDPOINT", serviceKey): endpoint,
970+
for _, ep := range endpoints {
971+
suffix := strings.ToUpper(ep.Protocol)
972+
key := fmt.Sprintf("AGENT_%s_%s_ENDPOINT", serviceKey, suffix)
973+
envVars[key] = ep.URL
877974
}
878975

879976
for key, value := range envVars {

0 commit comments

Comments
 (0)