feat: add backend plan mode checkpoints

Add backend support for plan-mode turn shaping and exit-plan review
checkpoints. Run-turn commands now accept an interaction mode,
plan-mode prompt guidance tells agents to produce a plan and call
exit_plan_mode, and the sidecar emits a structured
exit-plan-mode-requested event when the SDK raises that session event.

For now the backend intentionally treats exit_plan_mode as a turn
boundary and graceful-degradation review checkpoint. The current
Agent Framework GitHubCopilotAgent wrapper does not expose a clean way
to bridge the live CopilotSession back into same-turn exit-plan
resolution, so that follow-up remains documented for the frontend and a
future backend slice.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
David Kaya
2026-03-26 23:29:32 +01:00
co-authored by Copilot
parent c069b86add
commit 380e402512
11 changed files with 422 additions and 54 deletions
@@ -8,7 +8,8 @@ internal static class AgentInstructionComposer
PatternDefinitionDto pattern,
PatternAgentDefinitionDto agent,
int agentIndex,
string workspaceKind = "project")
string workspaceKind = "project",
string interactionMode = "interactive")
{
string baseInstructions = agent.Instructions.Trim();
string workspaceGuidance = string.Equals(workspaceKind, "scratchpad", StringComparison.OrdinalIgnoreCase)
@@ -20,6 +21,14 @@ internal static class AgentInstructionComposer
Answer conversationally and focus on the user's question directly.
"""
: string.Empty;
string planModeGuidance = string.Equals(interactionMode, "plan", StringComparison.OrdinalIgnoreCase)
? """
You are operating in plan mode.
Your job in this phase is to analyze the request, identify constraints, and produce a concrete implementation plan instead of carrying out the implementation.
Once the plan is ready, call the built-in `exit_plan_mode` tool so the host can present the plan for review.
Do not continue into implementation, file edits, builds, or tests after producing the plan unless the user explicitly asks to leave plan mode and proceed.
"""
: string.Empty;
if (string.Equals(pattern.Mode, "group-chat", StringComparison.OrdinalIgnoreCase))
{
@@ -37,12 +46,12 @@ internal static class AgentInstructionComposer
Focus on refining the answer already in progress.
""";
return JoinInstructionBlocks(baseInstructions, workspaceGuidance, groupChatGuidance);
return JoinInstructionBlocks(baseInstructions, workspaceGuidance, planModeGuidance, groupChatGuidance);
}
if (!string.Equals(pattern.Mode, "handoff", StringComparison.OrdinalIgnoreCase))
{
return JoinInstructionBlocks(baseInstructions, workspaceGuidance);
return JoinInstructionBlocks(baseInstructions, workspaceGuidance, planModeGuidance);
}
string runtimeGuidance = agentIndex == 0
@@ -60,7 +69,7 @@ internal static class AgentInstructionComposer
Do not push the actual work back to triage unless you are blocked or the request is clearly outside your specialty.
""";
return JoinInstructionBlocks(baseInstructions, workspaceGuidance, runtimeGuidance);
return JoinInstructionBlocks(baseInstructions, workspaceGuidance, planModeGuidance, runtimeGuidance);
}
private static string JoinInstructionBlocks(params string[] blocks)