MICROSOFT AGENT FRAMEWORK · 0.16.0-rc.1
Business contracts and validation
Move from free text to a validated proposal without granting it authority.
Objectives
- Structured output and schema
- Valid analysis and actionable draft
- Blocking questions and business validation
The contract between analysis and application
Free text suits human explanation; the application needs fields it can check. BacklogDraft carries Title, Kind, Priority, Component, Summary and ClarifyingQuestions. ChatResponseFormat.ForJsonSchema<BacklogDraft>() guides generation. The program then deserializes response.Text using System.Text.Json and handles JsonException and null before any action.
This avoids looking for the word “high” inside a sentence to decide on insertion. Structure makes errors checkable, but does not guarantee the model conclusion is correct. Historical RunAsync<T> signatures are not the procedure used by these programs.
Validate domains and bounds
public string[] Validate(bool forAction = true)
{
var errors = new List<string>();
if (!Text(Title, 120)) errors.Add("Title must contain 1 to 120 characters.");
if (!Text(Summary, 2000)) errors.Add("Summary must contain 1 to 2000 characters.");
if (Kind is not ("Bug" or "Feature" or "Question")) errors.Add("Unknown kind.");
if (Priority is not ("low" or "medium" or "high")) errors.Add("Unknown priority.");
if (!Catalog.Names.Contains(Component)) errors.Add("Unknown component.");
if (ClarifyingQuestions is null || ClarifyingQuestions.Length > 2
|| ClarifyingQuestions.Any(q => !Text(q, 300))) errors.Add("Invalid clarification questions.");
if (forAction && ClarifyingQuestions is { Length: > 0 }) errors.Add("Clarification is required before writing.");
return errors.ToArray();
Source code · Maf.Backlog · Folder
| Field | Condition |
|---|---|
| Title / Summary | Nonblank text, at most 120 / 2000 characters |
| Kind | Bug | Feature | Question |
| Priority | low | medium | high |
| Component | UI | API | Auth | Billing | Reporting | Storage | Other |
| ClarifyingQuestions | Non-null array, 0 to 2 nonblank texts, each ≤ 300 characters |
urgent and SecretAdmin can be perfectly valid JSON strings and remain forbidden. The host refuses instead of silently replacing urgent with high or adding a component. Catalog.Names is the trusted allowlist; a user-supplied document cannot extend it.
Useful analysis can block action
A request such as “It is sometimes slow” may provide neither a component nor reproduction steps. Asking one or two questions is a useful result. Validate(forAction: false) checks question shape; Validate() refuses a write while any question remains. An empty array means no clarification is declared; it does not certify that the model understood every fact.
Demo050 displays questions and errors; the user then submits a new, clarified request. There is no persistent clarification loop automatically merging turns. Do not silently add information to a draft after review.
Valid does not mean authorized
Demo050 can report Valid actionable draft while exposing no write tool. Business admissibility is a prerequisite. Host permission, approval of this proposal and its unused state still need checking. Even an admissible proposal can contain an incorrect business conclusion; human review concerns the exact content shown.
The historical EP001 counterexample used a refund: a threshold of 100 allowed an automatic proposal, 100–500 required escalation and above 500 required manual review. An “approved” JSON response for 1,250 could satisfy formatting while violating policy. The lesson is to code and test that constraint independently of the prompt. These amounts illustrate fictional policy; Demo100 now uses urgent and SecretAdmin in the backlog and executes no refund.
var errors = draft.Validate();
Console.WriteLine(JsonSerializer.Serialize(draft));
if (errors.Length != 0) { Console.WriteLine(string.Join(" ", errors)); continue; }
Console.WriteLine("Valid actionable draft; no write tool is exposed.");
Counterexamples to replay
Compare a clear Auth bug, an ambiguous request, urgent priority, an unknown component and a null question array. Deterministic tests construct these objects directly: they establish application refusal even if a live model does not generate that counterexample today. The test does not qualify the default model.
Try it, then connect tools
Prerequisites
Continue reading
Previous
Next
