Skip to content

Commit 08d03a0

Browse files
committed
Infer --m365 for blueprint/cleanup endpoint operations; address review comments
- setup blueprint --endpoint-only / --update-endpoint and cleanup blueprint --endpoint-only now infer --m365 (these always use the Teams Graph path), so the flag is no longer required; removed the non-M365 skip branches and the LogNonM365EndpointGuidance helper. - Reword TeamsGraphBackendConfigurator error logs from "backend configuration" to "messaging endpoint" (Grant review comment). - Sweep now-redundant --m365 from user-facing guidance, option help, README, and CHANGELOG; tighten the CHANGELOG --m365 entry to the shipped end state. - Replace the WithoutM365 exit-1 test with one asserting endpoint-only infers --m365 and registers.
1 parent 0f8b8a1 commit 08d03a0

8 files changed

Lines changed: 68 additions & 71 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ Agents provisioned before this release need `Agent365.Observability.OtelWrite` g
4040
- `setup requirements` runs without `a365.config.json` — system checks (PowerShell modules, Frontier enrollment) always run; client app checks run when a config file or Azure CLI session is available.
4141
- `--agent-name` and `--tenant-id` options added to `setup blueprint`, `setup permissions` (all subcommands), `create-instance`, `publish`, and `query-entra` — all commands can now resolve configuration from Entra ID without requiring `a365.config.json`.
4242
- `setup permissions custom --resource-app-id <guid> --scopes <scopes>` — apply inline custom API permissions to the agent blueprint without editing `a365.config.json`.
43-
- `--m365` opt-in flag on `a365 setup blueprint`, `a365 cleanup blueprint`, and `a365 setup all` — when set, the CLI registers or clears the agent blueprint's messaging endpoint via the Teams Graph backend configuration endpoint on MCP Platform. Default is **off**: without `--m365`, endpoint registration is skipped and the CLI points users at the Teams Developer Portal (https://learn.microsoft.com/en-us/microsoft-agent-365/developer/create-instance#1-configure-agent-in-teams-developer-portal) for manual configuration. Intended for M365 agents; opt-in because the Teams Graph rollout on MCP Platform is ongoing.
43+
- `--m365` opt-in flag on `a365 setup all` registers the agent blueprint's messaging endpoint via Teams Graph (MCP Platform); off by default, the step is skipped and you're pointed at the Teams Developer Portal. `setup blueprint --endpoint-only` / `--update-endpoint` and `cleanup blueprint --endpoint-only` always use this path and don't need the flag.
4444
- `--messaging-endpoint <url>` on `setup all` and `setup blueprint --endpoint-only` — supply the agent's HTTPS messaging endpoint directly; interactive `setup all --m365` prompts for it when none is configured.
4545
- Messaging endpoint row added to `a365 setup all` summary output, with "registered"/"reused"/"skipped (non-M365)"/"manual config required"/"failed" states. When registration can't complete, the summary surfaces an "Action Required" entry with the Teams Developer Portal URL so the user knows exactly what to do next.
4646
- Defensive fallback when the server rejects the new request with a known contract-mismatch signature — the CLI logs `"Automated messaging endpoint registration is not available for this tenant yet. You'll need to configure it manually."` and directs the user to the Teams Developer Portal. Same user-facing path is reused when registration fails because the signed-in user is not a blueprint owner.

src/Microsoft.Agents.A365.DevTools.Cli/Commands/CleanupCommand.cs

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,10 @@ private static Command CreateBlueprintCleanupCommand(
196196

197197
var m365Option = new Option<bool>(
198198
new[] { "--m365" },
199-
description: "Only meaningful with --endpoint-only. When set, clears the messaging endpoint from " +
200-
"Teams Graph via MCP Platform. Default is false (opt-in). Ignored (with a warning) " +
201-
"for full blueprint cleanup, since deleting the blueprint application cascades to " +
202-
"the backend configuration on the server side.");
199+
description: "Treat this agent as an M365 agent. Optional — --endpoint-only already clears the " +
200+
"messaging endpoint via Teams Graph automatically. Ignored (with a warning) for full " +
201+
"blueprint cleanup, since deleting the blueprint application removes the messaging " +
202+
"endpoint on the server side.");
203203

204204
var dryRunOption = new Option<bool>("--dry-run", "Show what would be deleted without making any changes");
205205

@@ -224,6 +224,10 @@ private static Command CreateBlueprintCleanupCommand(
224224
var dryRun = context.ParseResult.GetValueForOption(dryRunOption);
225225
var endpointOnly = context.ParseResult.GetValueForOption(endpointOnlyOption);
226226
var isM365 = context.ParseResult.GetValueForOption(m365Option);
227+
// Endpoint clearing goes through Teams Graph (the M365 path), so infer --m365 for
228+
// --endpoint-only — users shouldn't have to pass it (mirrors 'setup blueprint').
229+
if (endpointOnly)
230+
isM365 = true;
227231
var yes = context.ParseResult.GetValueForOption(yesOption);
228232
var ct = context.GetCancellationToken();
229233

@@ -276,15 +280,9 @@ private static Command CreateBlueprintCleanupCommand(
276280
agentBlueprintService.CustomClientAppId = config.ClientAppId;
277281
}
278282

279-
// If endpoint-only mode, only delete the messaging endpoint — gated on --m365.
283+
// Endpoint-only: clear just the messaging endpoint (--m365 is inferred above).
280284
if (endpointOnly)
281285
{
282-
if (!isM365)
283-
{
284-
SetupSubcommands.BlueprintSubcommand.LogNonM365EndpointGuidance(logger, "clear");
285-
return;
286-
}
287-
288286
await ExecuteEndpointOnlyCleanupAsync(logger, config, backendConfigurator, correlationId: correlationId);
289287
return;
290288
}
@@ -294,9 +292,9 @@ private static Command CreateBlueprintCleanupCommand(
294292
if (isM365)
295293
{
296294
logger.LogWarning(
297-
"--m365 has no effect on full blueprint cleanup. The Teams Graph backend " +
298-
"configuration is removed automatically when the blueprint is deleted. " +
299-
"Use 'a365 cleanup blueprint --endpoint-only --m365' to clear the endpoint " +
295+
"--m365 has no effect on full blueprint cleanup. The messaging endpoint is " +
296+
"removed automatically when the blueprint is deleted. " +
297+
"Use 'a365 cleanup blueprint --endpoint-only' to clear the endpoint " +
300298
"while preserving the blueprint.");
301299
}
302300

@@ -529,10 +527,10 @@ private static Command CreateBlueprintCleanupCommand(
529527

530528
logger.LogInformation("Agent blueprint application deleted successfully");
531529

532-
// Teams Graph backend configuration is a child resource of the blueprint and is
533-
// removed on the server side when the blueprint is deleted. No separate clear
534-
// call is needed here. Use `a365 cleanup blueprint --endpoint-only --m365` to
535-
// clear just the backend configuration while preserving the blueprint.
530+
// The messaging endpoint is a child resource of the blueprint and is removed on the
531+
// server side when the blueprint is deleted. No separate clear call is needed here.
532+
// Use `a365 cleanup blueprint --endpoint-only` to clear just the messaging endpoint
533+
// while preserving the blueprint.
536534
PrintOrphanSummary(logger, failedResources);
537535

538536
// Clear configuration after successful blueprint deletion

src/Microsoft.Agents.A365.DevTools.Cli/Commands/SetupSubcommands/AllSubcommand.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ public static Command CreateCommand(
162162
"When supplied, the endpoint is registered as part of setup. When omitted, an\n" +
163163
"interactive run prompts for it and a non-interactive run defers it — the endpoint\n" +
164164
"is a post-deploy artifact, so it can be set later with\n" +
165-
"'a365 setup blueprint --endpoint-only --m365 --messaging-endpoint <url>'.");
165+
"'a365 setup blueprint --endpoint-only --messaging-endpoint <url>'.");
166166

167167
command.AddOption(verboseOption);
168168
command.AddOption(dryRunOption);
@@ -887,7 +887,7 @@ internal static async Task ExecuteMessagingEndpointStepAsync(SetupContext ctx)
887887
ctx.Results.MessagingEndpointResult = Models.EndpointRegistrationResult.Failed;
888888
ctx.Results.MessagingEndpointFailureReason = MessagingEndpointFailureReasons.BlueprintMissing;
889889
ctx.Results.MessagingEndpoint = ctx.Config.MessagingEndpoint;
890-
ctx.Results.Warnings.Add("Messaging endpoint: agent blueprint ID is missing, so endpoint registration was not attempted. Resolve the blueprint creation failure first, then re-run 'a365 setup blueprint --endpoint-only --m365'.");
890+
ctx.Results.Warnings.Add("Messaging endpoint: agent blueprint ID is missing, so endpoint registration was not attempted. Resolve the blueprint creation failure first, then re-run 'a365 setup blueprint --endpoint-only'.");
891891
return;
892892
}
893893

src/Microsoft.Agents.A365.DevTools.Cli/Commands/SetupSubcommands/BlueprintSubcommand.cs

Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,9 @@ public static Command CreateCommand(
172172

173173
var m365Option = new Option<bool>(
174174
"--m365",
175-
description: "Treat this agent as an M365 agent. Only affects --endpoint-only and --update-endpoint " +
176-
"on this command. To configure the messaging endpoint as part of full setup, use " +
177-
"'a365 setup all --m365'.");
175+
description: "Treat this agent as an M365 agent. Optional on this command — --endpoint-only and " +
176+
"--update-endpoint already use the M365 (Teams Graph) path automatically. To configure " +
177+
"the messaging endpoint as part of full setup, use 'a365 setup all --m365'.");
178178

179179
var showSecretOption = new Option<bool>(
180180
"--show-secret",
@@ -210,6 +210,11 @@ public static Command CreateCommand(
210210
var messagingEndpointFlag = context.ParseResult.GetValueForOption(messagingEndpointOption)?.Trim();
211211
var skipRequirements = context.ParseResult.GetValueForOption(skipRequirementsOption);
212212
var isM365 = context.ParseResult.GetValueForOption(m365Option);
213+
// Endpoint operations always go through Teams Graph (the M365 path), so infer --m365 for
214+
// --endpoint-only / --update-endpoint — users shouldn't have to pass it. ('setup all' keeps
215+
// --m365 explicit because there it also affects the granted permission set.)
216+
if (endpointOnly || !string.IsNullOrWhiteSpace(updateEndpoint))
217+
isM365 = true;
213218
var showSecret = context.ParseResult.GetValueForOption(showSecretOption);
214219
var ct = context.GetCancellationToken();
215220

@@ -357,15 +362,9 @@ public static Command CreateCommand(
357362
// target the correct national cloud endpoint (commercial by default).
358363
graphApiService.GraphBaseUrl = setupConfig.GraphBaseUrl;
359364

360-
// Handle --update-endpoint flag
365+
// Handle --update-endpoint flag (--m365 is inferred for endpoint operations).
361366
if (!string.IsNullOrWhiteSpace(updateEndpoint))
362367
{
363-
if (!isM365)
364-
{
365-
LogNonM365EndpointGuidance(logger, "update");
366-
return;
367-
}
368-
369368
await UpdateEndpointAsync(
370369
config.FullName,
371370
updateEndpoint,
@@ -405,18 +404,12 @@ await RequirementsSubcommand.RunChecksOrExitAsync(
405404
{
406405
logger.LogInformation(
407406
"Note: --m365 has no effect on 'setup blueprint' by itself. Use 'a365 setup all --m365' to register the messaging endpoint, " +
408-
"or 'a365 setup blueprint --endpoint-only --m365' after the blueprint exists.");
407+
"or 'a365 setup blueprint --endpoint-only' after the blueprint exists.");
409408
}
410409

411-
// Handle --endpoint-only flag — only wired up for --m365 agents.
410+
// Handle --endpoint-only flag (--m365 is inferred for endpoint operations).
412411
if (endpointOnly)
413412
{
414-
if (!isM365)
415-
{
416-
LogNonM365EndpointGuidance(logger, "register");
417-
return;
418-
}
419-
420413
var endpointResult = await RegisterEndpointAndSyncAsync(
421414
config.FullName,
422415
logger,
@@ -462,22 +455,6 @@ await CreateBlueprintImplementationAsync(
462455
return command;
463456
}
464457

465-
/// <summary>
466-
/// Logs the standard "non-M365 agent" message directing the user to configure the messaging
467-
/// endpoint in the Teams Developer Portal. Used when the user did not pass --m365 on commands
468-
/// that would otherwise call into the Teams Graph backend configurator.
469-
/// </summary>
470-
/// <param name="logger">Logger instance.</param>
471-
/// <param name="action">Either "register" or "update" — included in the skip message.</param>
472-
internal static void LogNonM365EndpointGuidance(ILogger logger, string action)
473-
{
474-
logger.LogInformation(
475-
"Skipping messaging endpoint {Action} — this command only applies to M365 agents. " +
476-
"Pass --m365 to opt in, or configure the endpoint manually in the Teams Developer Portal:",
477-
action);
478-
logger.LogInformation(" {Url}", Constants.ConfigConstants.TeamsDeveloperPortalConfigureEndpointUrl);
479-
}
480-
481458
/// <summary>
482459
/// Validates that mutually exclusive command options are not used together.
483460
/// </summary>

src/Microsoft.Agents.A365.DevTools.Cli/Commands/SetupSubcommands/README.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,22 +96,21 @@ a365 setup all --authmode both
9696

9797
### Messaging endpoint (M365 agents)
9898

99-
The `--m365` flag opts into registering the messaging endpoint with Teams Graph via MCP Platform. It is **off by default** — without it, `--endpoint-only`, `--update-endpoint`, and the messaging-endpoint step in `setup all` skip the API call and point you at the Teams Developer Portal for manual configuration.
99+
The `--m365` flag opts into registering the messaging endpoint with Teams Graph via MCP Platform. On `setup all` it is **off by default** — without it, the messaging-endpoint step is skipped and you're pointed at the Teams Developer Portal for manual configuration. The `--endpoint-only` and `--update-endpoint` operations always use the Teams Graph path, so `--m365` is inferred there and doesn't need to be passed.
100100

101101
```bash
102102
# Full setup including messaging endpoint registration
103103
a365 setup all --m365
104104

105-
# Register the messaging endpoint only (existing blueprint)
106-
a365 setup blueprint --endpoint-only --m365
105+
# Register the messaging endpoint only (existing blueprint; --m365 is inferred)
106+
a365 setup blueprint --endpoint-only
107107

108108
# Update the endpoint URL (clears and re-registers)
109-
a365 setup blueprint --update-endpoint https://your-host.example.com/api/messages --m365
110-
111-
# Non-M365 agent: CLI prints the Teams Developer Portal link and skips the API call
112-
a365 setup blueprint --endpoint-only
109+
a365 setup blueprint --update-endpoint https://your-host.example.com/api/messages
113110
```
114111

112+
If the tenant's Teams Graph backend can't service the request, the CLI logs a contract-mismatch notice and points to the Teams Developer Portal for manual configuration.
113+
115114
When the server rejects the request with a recognized contract-mismatch signature (today: the pre-migration Azure Bot Service validator), the CLI logs at INFO:
116115

117116
```

src/Microsoft.Agents.A365.DevTools.Cli/Commands/SetupSubcommands/SetupHelpers.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -900,20 +900,20 @@ public static void DisplaySetupSummary(SetupResults results, ILogger logger)
900900
logger.LogInformation("");
901901
logger.LogInformation(" B. Ask the blueprint owner to add you as a co-owner, then re-run just");
902902
logger.LogInformation(" the endpoint step (no need to re-run the full setup):");
903-
logger.LogInformation(" a365 setup blueprint --endpoint-only --m365");
903+
logger.LogInformation(" a365 setup blueprint --endpoint-only");
904904
}
905905
else if (string.Equals(results.MessagingEndpointFailureReason, MessagingEndpointFailureReasons.BlueprintMissing, StringComparison.Ordinal))
906906
{
907907
logger.LogInformation(" {N}. Messaging endpoint — not attempted because agent blueprint creation did not", actionCount);
908908
logger.LogInformation(" complete. Resolve the blueprint step (see errors above), then re-run just");
909909
logger.LogInformation(" the endpoint step:");
910-
logger.LogInformation(" a365 setup blueprint --endpoint-only --m365");
910+
logger.LogInformation(" a365 setup blueprint --endpoint-only");
911911
}
912912
else
913913
{
914914
logger.LogInformation(" {N}. Messaging endpoint — registration failed; see the error above for details.", actionCount);
915915
logger.LogInformation(" To retry after addressing the issue, re-run just the endpoint step:");
916-
logger.LogInformation(" a365 setup blueprint --endpoint-only --m365");
916+
logger.LogInformation(" a365 setup blueprint --endpoint-only");
917917
logger.LogInformation("");
918918
logger.LogInformation(" Or configure the endpoint manually in the Teams Developer Portal:");
919919
logger.LogInformation(" {Url}", ConfigConstants.TeamsDeveloperPortalConfigureEndpointUrl);
@@ -989,7 +989,7 @@ public static void DisplaySetupSummary(SetupResults results, ILogger logger)
989989
nextStepLines.Add(() =>
990990
{
991991
logger.LogInformation(" Messaging endpoint — set it once your agent is deployed:");
992-
logger.LogInformation(" a365 setup blueprint --endpoint-only --m365 --messaging-endpoint <https-url>");
992+
logger.LogInformation(" a365 setup blueprint --endpoint-only --messaging-endpoint <https-url>");
993993
logger.LogInformation(" Or register it manually in the Teams Developer Portal:");
994994
logger.LogInformation(" {Url}", ConfigConstants.TeamsDeveloperPortalConfigureEndpointUrl);
995995
});

src/Microsoft.Agents.A365.DevTools.Cli/Services/TeamsGraphBackendConfigurator.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public TeamsGraphBackendConfigurator(
5252

5353
if (string.IsNullOrEmpty(tenantId))
5454
{
55-
_logger.LogError("Could not determine tenant ID for backend configuration");
55+
_logger.LogError("Could not determine tenant ID to register the messaging endpoint.");
5656
return (EndpointRegistrationResult.Failed, "Other");
5757
}
5858

@@ -124,7 +124,7 @@ public TeamsGraphBackendConfigurator(
124124
return (EndpointRegistrationResult.SkippedContractMismatch, null);
125125
}
126126

127-
_logger.LogError("Failed to set backend configuration. Status: {Status}", response.StatusCode);
127+
_logger.LogError("Failed to register the messaging endpoint. Status: {Status}", response.StatusCode);
128128
_logger.LogError("Response: {Error}", errorContent);
129129
return (EndpointRegistrationResult.Failed, ClassifyFailureReason(errorContent));
130130
}
@@ -143,7 +143,7 @@ public TeamsGraphBackendConfigurator(
143143
}
144144
catch (Exception ex)
145145
{
146-
_logger.LogError(ex, "Unexpected error setting backend configuration: {Message}", ex.Message);
146+
_logger.LogError(ex, "Unexpected error registering the messaging endpoint: {Message}", ex.Message);
147147
return (EndpointRegistrationResult.Failed, ClassifyFailureReason(ex.Message));
148148
}
149149
}
@@ -164,7 +164,7 @@ public async Task<bool> ClearBackendConfigurationAsync(
164164

165165
if (string.IsNullOrEmpty(tenantId))
166166
{
167-
_logger.LogError("Could not determine tenant ID for backend configuration");
167+
_logger.LogError("Could not determine tenant ID to remove the messaging endpoint.");
168168
return false;
169169
}
170170

@@ -267,7 +267,7 @@ public async Task<bool> ClearBackendConfigurationAsync(
267267
}
268268
catch (Exception ex)
269269
{
270-
_logger.LogError(ex, "Unexpected error clearing backend configuration: {Message}", ex.Message);
270+
_logger.LogError(ex, "Unexpected error removing the messaging endpoint: {Message}", ex.Message);
271271
return false;
272272
}
273273
}

0 commit comments

Comments
 (0)