@polymorphism-tech/morph-spec 7.0.0 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +367 -367
- package/framework/agents.json +132 -127
- package/framework/rubrics/backend.json +41 -36
- package/framework/rules/ai-agents-standards.md +45 -15
- package/framework/rules/neon-standards.md +25 -26
- package/framework/standards/STANDARDS.json +1729 -1133
- package/framework/standards/ai-agents/agent-session.md +160 -0
- package/framework/standards/ai-agents/batching.md +193 -0
- package/framework/standards/ai-agents/context-providers.md +188 -0
- package/framework/standards/ai-agents/mcp-server.md +250 -0
- package/framework/standards/ai-agents/mcp-tools.md +197 -0
- package/framework/standards/ai-agents/middleware-patterns.md +207 -0
- package/framework/standards/ai-agents/modalities-image-gen.md +173 -0
- package/framework/standards/ai-agents/modalities-speech-to-text.md +171 -0
- package/framework/standards/ai-agents/modalities-text-to-speech.md +181 -0
- package/framework/standards/ai-agents/modalities-vision.md +201 -0
- package/framework/standards/ai-agents/multi-agent-patterns.md +155 -0
- package/framework/standards/ai-agents/production.md +114 -258
- package/framework/standards/ai-agents/prompts-in-db.md +214 -0
- package/framework/standards/ai-agents/providers/model-registry.md +158 -0
- package/framework/standards/ai-agents/rag-custom-pgvector.md +243 -0
- package/framework/standards/ai-agents/service-tier-flex.md +135 -0
- package/framework/standards/ai-agents/setup.md +142 -316
- package/framework/standards/ai-agents/structured-output.md +249 -0
- package/framework/standards/ai-agents/sweet-spot.md +109 -0
- package/framework/standards/ai-agents/workflows.md +114 -284
- package/framework/standards/architecture/vertical-slice/vertical-slice.md +433 -429
- package/framework/standards/backend/api/validation.md +92 -88
- package/framework/standards/backend/database/postgresql/database.md +336 -332
- package/framework/standards/backend/database/vector-search-rag.md +599 -541
- package/framework/standards/backend/dotnet/fluent-validation-vsa.md +4 -0
- package/framework/standards/backend/dotnet/result-pattern.md +4 -0
- package/framework/standards/backend/dotnet/scalar-ui.md +176 -172
- package/framework/standards/backend/dotnet/scrutor.md +4 -0
- package/framework/standards/backend/dotnet/vsa-handler-patterns.md +278 -274
- package/framework/standards/backend/integrations/asaas/asaas-api.md +260 -216
- package/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +354 -350
- package/framework/standards/backend/integrations/neon-auth/neon-auth.md +30 -19
- package/framework/standards/backend/integrations/resend/resend-email.md +400 -385
- package/framework/standards/data/nosql/cache/redis.md +106 -97
- package/framework/standards/data/nosql/cosmos-db.md +127 -118
- package/framework/standards/data/vector-search/rag-chunking.md +113 -104
- package/framework/standards/frontend/design-system/ai-image-generation.md +4 -0
- package/framework/standards/frontend/design-system/animations.md +164 -160
- package/framework/standards/frontend/design-system/naming.md +68 -64
- package/framework/standards/frontend/gsap/gsap-core.md +14 -8
- package/framework/standards/frontend/gsap/gsap-plugins.md +26 -21
- package/framework/standards/frontend/gsap/gsap-scrolltrigger.md +9 -7
- package/framework/standards/frontend/nextjs/app-router.md +127 -123
- package/framework/standards/frontend/nextjs/components.md +136 -132
- package/framework/standards/frontend/nextjs/data-fetching.md +130 -126
- package/framework/standards/frontend/nextjs/forms.md +134 -128
- package/framework/standards/frontend/nextjs/motion-patterns.md +328 -322
- package/framework/standards/frontend/nextjs/naming-conventions.md +71 -67
- package/framework/standards/frontend/nextjs/nextjs-patterns.md +229 -225
- package/framework/standards/frontend/nextjs/project-structure.md +106 -102
- package/framework/standards/frontend/nextjs/state-management.md +76 -72
- package/framework/standards/frontend/nextjs/testing.md +115 -111
- package/framework/standards/infrastructure/docker/easypanel-deploy.md +196 -192
- package/framework/standards/infrastructure/neon/neon-pgrag.md +6 -2
- package/framework/standards/infrastructure/neon/neon-pgvector.md +4 -0
- package/framework/standards/infrastructure/neon/neon-setup.md +5 -1
- package/framework/standards/integration/mcp/mcp-tools.md +471 -462
- package/framework/templates/REGISTRY.json +1745 -1239
- package/framework/templates/code/dotnet/ai-agents/AgentBootstrap.cs.template +39 -0
- package/framework/templates/code/dotnet/ai-agents/EmbeddingService.cs.template +68 -0
- package/framework/templates/code/dotnet/ai-agents/ModelRegistry.cs.template +117 -0
- package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +95 -0
- package/framework/templates/code/dotnet/ai-agents/ResilientToolMiddleware.cs.template +61 -0
- package/framework/templates/code/dotnet/ai-agents/VectorSearchTool.cs.template +107 -0
- package/framework/templates/code/dotnet/ai-agents/model-registry.json.template +58 -0
- package/framework/templates/code/sql/ai-agents/agent-prompts-migration.sql.template +58 -0
- package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -0
- package/package.json +89 -83
- package/src/core/templates/template-registry.js +289 -256
- package/src/lib/generators/context-generator.js +516 -518
- package/src/lib/generators/scaffold-generator.js +23 -26
- package/framework/standards/infrastructure/neon/neon-semantic-kernel.md +0 -310
- package/framework/templates/integrations/semantic-kernel-neon.cs +0 -125
|
@@ -1,418 +1,244 @@
|
|
|
1
|
-
# Microsoft Agent Framework
|
|
1
|
+
# Microsoft Agent Framework — Setup Guide (.NET 10)
|
|
2
2
|
|
|
3
|
-
> **Scope:**
|
|
4
|
-
> **Layer:** 0 (always
|
|
5
|
-
> **Keywords:**
|
|
6
|
-
> **
|
|
3
|
+
> **Scope:** stacks=["dotnet"]
|
|
4
|
+
> **Layer:** 0 (always-load via persona maf-expert)
|
|
5
|
+
> **Keywords:** maf setup, microsoft agents ai, chatclient, ai agent, agent framework, agent dotnet, AsAIAgent
|
|
6
|
+
> **Read by Claude in:** plan (pra citar pacote em tasks.json) + implement (pra escrever .csproj e Program.cs)
|
|
7
7
|
|
|
8
|
-
**
|
|
9
|
-
Semantic Kernel is superseded. Do NOT use `Kernel`, `KernelFunction`, or `InvokePromptAsync`.
|
|
8
|
+
**Verified against:** Microsoft.Agents.AI 1.0 GA (abril/2026). Last-verified: 2026-05-19.
|
|
10
9
|
|
|
11
10
|
---
|
|
12
11
|
|
|
13
|
-
##
|
|
12
|
+
## Provider philosophy — direct models always
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
<!-- .csproj -->
|
|
17
|
-
<!-- Microsoft.Extensions.AI — STABLE abstractions for IChatClient, AIFunctionFactory, tools -->
|
|
18
|
-
<PackageReference Include="Microsoft.Extensions.AI" Version="9.5.0" />
|
|
19
|
-
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="9.3.0-preview.*" />
|
|
14
|
+
This framework is **provider-agnostic**. There is no "primary" provider hardcoded. Every model is reached as a **direct model** (you call the model API directly) — never via a hosted agent service. Hosted services lag 6-9 months on models and remove control.
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<PackageReference Include="Azure.Identity" Version="1.*" />
|
|
16
|
+
First-class providers: **OpenAI, Google (Gemini), Anthropic (Claude), Ollama** (local/on-prem).
|
|
17
|
+
Azure OpenAI is also a direct model but is **not a default** — see note in §3.4.
|
|
24
18
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
19
|
+
The concrete model choice lives in the project's Model Registry, not in this standard. See `ai-agents-providers-model-registry`.
|
|
20
|
+
|
|
21
|
+
## Decision tree (when reading this in plan phase)
|
|
28
22
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
```
|
|
24
|
+
Está adicionando um agente AI a um projeto .NET?
|
|
25
|
+
├─ Sim → use este standard + ai-agents-sweet-spot + ai-agents-providers-model-registry
|
|
26
|
+
│ ├─ Projeto tem >1 modelo ou >1 provider? → SEMPRE use Model Registry
|
|
27
|
+
│ ├─ Provider OpenAI? → §3.1
|
|
28
|
+
│ ├─ Provider Ollama (local)? → §3.2
|
|
29
|
+
│ ├─ Provider Google / Anthropic? → §3.3
|
|
30
|
+
│ └─ Provider Azure OpenAI (data residency)? → §3.4 (nota, não default)
|
|
31
|
+
└─ Não → este standard não se aplica
|
|
32
|
+
```
|
|
33
33
|
|
|
34
34
|
---
|
|
35
35
|
|
|
36
|
-
##
|
|
36
|
+
## 1. Packages (NuGet)
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
using Azure.AI.OpenAI;
|
|
40
|
-
using Azure.Identity;
|
|
41
|
-
using Microsoft.Extensions.AI;
|
|
42
|
-
|
|
43
|
-
AIAgent agent = new AzureOpenAIClient(
|
|
44
|
-
new Uri("https://your-resource.openai.azure.com/"),
|
|
45
|
-
new AzureCliCredential())
|
|
46
|
-
.GetChatClient("gpt-4o-mini")
|
|
47
|
-
.AsAIAgent(instructions: "You are a helpful assistant.");
|
|
38
|
+
**Required for any MAF project:**
|
|
48
39
|
|
|
49
|
-
|
|
40
|
+
```xml
|
|
41
|
+
<PackageReference Include="Microsoft.Agents.AI" Version="1.0.*" />
|
|
50
42
|
```
|
|
51
43
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
## Setup by Provider
|
|
44
|
+
**Provider-specific (escolha conforme o Model Registry do projeto):**
|
|
55
45
|
|
|
56
|
-
|
|
46
|
+
```xml
|
|
47
|
+
<!-- OpenAI direct -->
|
|
48
|
+
<PackageReference Include="Microsoft.Agents.AI.OpenAI" Version="1.0.*" />
|
|
49
|
+
<PackageReference Include="OpenAI" Version="2.*" />
|
|
57
50
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
using Azure.Identity;
|
|
61
|
-
using Microsoft.Extensions.AI;
|
|
51
|
+
<!-- Ollama (local / on-prem) — usa o mesmo OpenAI-compatible client -->
|
|
52
|
+
<PackageReference Include="OpenAI" Version="2.*" />
|
|
62
53
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
return new AzureOpenAIClient(
|
|
67
|
-
new Uri(cfg["AzureOpenAI:Endpoint"]!),
|
|
68
|
-
new DefaultAzureCredential()) // Managed Identity
|
|
69
|
-
.GetChatClient(cfg["AzureOpenAI:DeploymentName"] ?? "gpt-4o-mini")
|
|
70
|
-
.AsIChatClient();
|
|
71
|
-
});
|
|
54
|
+
<!-- Google Gemini — SDK verificado no standard model-registry.md -->
|
|
55
|
+
<!-- Anthropic Claude — SDK verificado no standard model-registry.md -->
|
|
56
|
+
<!-- Azure OpenAI (somente se data residency exigir) — Azure.AI.OpenAI 2.* + Azure.Identity 1.* -->
|
|
72
57
|
```
|
|
73
58
|
|
|
74
|
-
|
|
59
|
+
> The `.AsIChatClient()` extension on `OpenAI.ChatClient` comes from `Microsoft.Agents.AI.OpenAI`. The `IChatClient` abstraction itself lives in `Microsoft.Extensions.AI` (a transitive dependency of `Microsoft.Agents.AI`) — code that uses `IChatClient` needs `using Microsoft.Extensions.AI;`.
|
|
75
60
|
|
|
76
|
-
|
|
77
|
-
using OpenAI;
|
|
78
|
-
using Microsoft.Extensions.AI;
|
|
61
|
+
> Os pacotes de Google e Anthropic mudam de nome/versão com frequência. O standard `ai-agents-providers-model-registry` mantém a lista verificada com data. Não trave SDK aqui.
|
|
79
62
|
|
|
80
|
-
|
|
81
|
-
{
|
|
82
|
-
var cfg = sp.GetRequiredService<IConfiguration>();
|
|
83
|
-
return new ChatClient(
|
|
84
|
-
"gpt-4o-mini",
|
|
85
|
-
new ApiKeyCredential(cfg["GitHub:Token"]!),
|
|
86
|
-
new OpenAIClientOptions { Endpoint = new Uri("https://models.github.ai/inference") })
|
|
87
|
-
.AsIChatClient();
|
|
88
|
-
});
|
|
89
|
-
```
|
|
63
|
+
**Optional (only when feature requires):**
|
|
90
64
|
|
|
91
|
-
|
|
65
|
+
```xml
|
|
66
|
+
<!-- Hosting helpers (AddAIAgent, AddSequentialWorkflow) -->
|
|
67
|
+
<PackageReference Include="Microsoft.Agents.AI.Hosting" Version="1.0.*" />
|
|
92
68
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
new ChatClient("llama3.2:3b",
|
|
96
|
-
endpoint: new Uri("http://localhost:11434"))
|
|
97
|
-
.AsIChatClient());
|
|
69
|
+
<!-- A2A protocol -->
|
|
70
|
+
<PackageReference Include="Microsoft.Agents.AI.A2A" Version="1.0.*" />
|
|
98
71
|
```
|
|
99
72
|
|
|
100
|
-
|
|
73
|
+
**Forbidden in new MAF projects:**
|
|
101
74
|
|
|
102
|
-
|
|
75
|
+
- `Microsoft.SemanticKernel.*` — superseded by MAF, do not introduce.
|
|
76
|
+
- `Microsoft.Extensions.AI.OpenAI` 9.* — replaced by `Microsoft.Agents.AI.OpenAI` in GA.
|
|
77
|
+
- Hosted agent services (Foundry Agent Service, etc.) — use direct models.
|
|
103
78
|
|
|
104
|
-
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## 2. Quick Start (canonical minimal agent)
|
|
105
82
|
|
|
106
83
|
```csharp
|
|
84
|
+
using Microsoft.Agents.AI;
|
|
107
85
|
using Microsoft.Extensions.AI;
|
|
86
|
+
using OpenAI;
|
|
87
|
+
using OpenAI.Chat;
|
|
108
88
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
private readonly ILogger<OrderAnalysisAgent> _logger;
|
|
113
|
-
|
|
114
|
-
public OrderAnalysisAgent(IChatClient chatClient, ILogger<OrderAnalysisAgent> logger)
|
|
115
|
-
{
|
|
116
|
-
_chatClient = chatClient;
|
|
117
|
-
_logger = logger;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
public async Task<string> AnalyzeAsync(Order order, CancellationToken ct = default)
|
|
121
|
-
{
|
|
122
|
-
var agent = new ChatClientAgent(
|
|
123
|
-
_chatClient,
|
|
124
|
-
new ChatClientAgentOptions
|
|
125
|
-
{
|
|
126
|
-
Name = "OrderAnalyzer",
|
|
127
|
-
Instructions = """
|
|
128
|
-
You are an e-commerce order analyst.
|
|
129
|
-
Analyze the order and return:
|
|
130
|
-
1. Summary
|
|
131
|
-
2. Upsell suggestions
|
|
132
|
-
3. Cancellation risk (low/medium/high)
|
|
133
|
-
Be concise.
|
|
134
|
-
"""
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
_logger.LogInformation("Analyzing order {OrderNumber}", order.OrderNumber);
|
|
138
|
-
|
|
139
|
-
var response = await agent.RunAsync(
|
|
140
|
-
$"Order: {order.OrderNumber}, Total: {order.Total:C}, Items: {order.Items.Count}",
|
|
141
|
-
cancellationToken: ct);
|
|
142
|
-
|
|
143
|
-
return response.Text;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### Using AsAIAgent (Shorthand)
|
|
149
|
-
|
|
150
|
-
```csharp
|
|
151
|
-
AIAgent agent = chatClient.AsAIAgent(
|
|
152
|
-
instructions: "You are a helpful assistant.",
|
|
153
|
-
name: "MyAgent");
|
|
89
|
+
AIAgent agent = new ChatClient(model: "gpt-4o-mini", apiKey: "<from-config>")
|
|
90
|
+
.AsIChatClient()
|
|
91
|
+
.AsAIAgent(instructions: "You are a helpful assistant.");
|
|
154
92
|
|
|
155
|
-
var response = await agent.RunAsync("
|
|
93
|
+
var response = await agent.RunAsync("Analyze this order.");
|
|
156
94
|
Console.WriteLine(response.Text);
|
|
157
95
|
```
|
|
158
96
|
|
|
97
|
+
This snippet is the baseline. In a real project you never hardcode the model — use the Model Registry (`ai-agents-providers-model-registry`). Anything more complex (DI, tools, structured output, RAG) layers on top via the other ai-agents standards.
|
|
98
|
+
|
|
159
99
|
---
|
|
160
100
|
|
|
161
|
-
##
|
|
101
|
+
## 3. Setup by Provider
|
|
102
|
+
|
|
103
|
+
> In any project with >1 model or >1 provider, **do not register `IChatClient` directly** — use the Model Registry (`ai-agents-providers-model-registry`). The snippets below show the raw client construction the registry wraps.
|
|
162
104
|
|
|
163
|
-
###
|
|
105
|
+
### 3.1 OpenAI direct (most common)
|
|
164
106
|
|
|
165
107
|
```csharp
|
|
108
|
+
using OpenAI;
|
|
109
|
+
using OpenAI.Chat;
|
|
166
110
|
using Microsoft.Extensions.AI;
|
|
167
111
|
|
|
168
|
-
|
|
112
|
+
builder.Services.AddSingleton<IChatClient>(sp =>
|
|
169
113
|
{
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
[Description("City name")] string city,
|
|
177
|
-
CancellationToken ct = default)
|
|
178
|
-
{
|
|
179
|
-
var weather = await _weatherService.GetCurrentAsync(city, ct);
|
|
180
|
-
return $"Temp: {weather.Temperature}°C, Condition: {weather.Condition}";
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
[Description("Gets weather forecast for upcoming days")]
|
|
184
|
-
public async Task<string> GetForecastAsync(
|
|
185
|
-
[Description("City name")] string city,
|
|
186
|
-
[Description("Number of days")] int days = 3,
|
|
187
|
-
CancellationToken ct = default)
|
|
188
|
-
{
|
|
189
|
-
var forecast = await _weatherService.GetForecastAsync(city, days, ct);
|
|
190
|
-
return string.Join("\n", forecast.Select(f => $"{f.Date:dd/MM}: {f.Temperature}°C"));
|
|
191
|
-
}
|
|
192
|
-
}
|
|
114
|
+
var cfg = sp.GetRequiredService<IConfiguration>();
|
|
115
|
+
return new ChatClient(
|
|
116
|
+
model: cfg["OpenAI:Model"] ?? "gpt-4o-mini",
|
|
117
|
+
apiKey: cfg["OpenAI:ApiKey"]!)
|
|
118
|
+
.AsIChatClient();
|
|
119
|
+
});
|
|
193
120
|
```
|
|
194
121
|
|
|
195
|
-
###
|
|
122
|
+
### 3.2 Ollama (local dev / on-prem)
|
|
123
|
+
|
|
124
|
+
Ollama exposes an OpenAI-compatible endpoint — use the same `ChatClient`:
|
|
196
125
|
|
|
197
126
|
```csharp
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
[
|
|
210
|
-
AIFunctionFactory.Create(weatherFunctions.GetWeatherAsync),
|
|
211
|
-
AIFunctionFactory.Create(weatherFunctions.GetForecastAsync)
|
|
212
|
-
]
|
|
213
|
-
}
|
|
214
|
-
});
|
|
127
|
+
using OpenAI;
|
|
128
|
+
using OpenAI.Chat;
|
|
129
|
+
using System.ClientModel;
|
|
130
|
+
using Microsoft.Extensions.AI;
|
|
131
|
+
|
|
132
|
+
builder.Services.AddSingleton<IChatClient>(sp =>
|
|
133
|
+
new ChatClient(
|
|
134
|
+
model: "llama3.2:3b",
|
|
135
|
+
credential: new ApiKeyCredential("ollama"), // any non-empty string
|
|
136
|
+
options: new OpenAIClientOptions { Endpoint = new Uri("http://localhost:11434/v1") })
|
|
137
|
+
.AsIChatClient());
|
|
215
138
|
```
|
|
216
139
|
|
|
217
|
-
|
|
140
|
+
> Models < 3B params often fail tool calling. Use Ollama only for non-tool agents in dev.
|
|
218
141
|
|
|
219
|
-
|
|
220
|
-
[Description("Gets the current date and time")]
|
|
221
|
-
static string GetCurrentDateTime() => DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
|
142
|
+
### 3.3 Google (Gemini) / Anthropic (Claude)
|
|
222
143
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
144
|
+
Both are first-class providers reached as direct models. The exact NuGet SDK and client construction are documented (with verification date) in `ai-agents-providers-model-registry` §providers — that standard is the single source of truth for provider SDKs, since they change names/versions often.
|
|
145
|
+
|
|
146
|
+
### 3.4 Azure OpenAI (note — not a default)
|
|
147
|
+
|
|
148
|
+
Azure OpenAI is also a direct model, but requires an Azure resource + deployment per model. It is **not a default provider** in this framework — projects deploy to VPS, not Azure. Add an Azure branch to the Model Registry only when a client explicitly requires data residency in a specific Azure region. The pattern: `new AzureOpenAIClient(endpoint, credential).GetChatClient(deployment).AsIChatClient()`.
|
|
227
149
|
|
|
228
150
|
---
|
|
229
151
|
|
|
230
|
-
##
|
|
152
|
+
## 4. DI Registration (keyed agents)
|
|
231
153
|
|
|
232
|
-
|
|
154
|
+
> The `builder.AddAIAgent(...)` extension requires the `Microsoft.Agents.AI.Hosting` package (see §1 Optional). For projects that register agents manually without `AddAIAgent`, the base `Microsoft.Agents.AI` package is enough.
|
|
233
155
|
|
|
234
156
|
```csharp
|
|
235
157
|
// Program.cs
|
|
236
158
|
builder.AddAIAgent("OrderAnalyzer", (sp, key) =>
|
|
237
159
|
{
|
|
238
160
|
var chatClient = sp.GetRequiredService<IChatClient>();
|
|
239
|
-
var orderFunctions = sp.GetRequiredService<OrderFunctions>();
|
|
240
|
-
|
|
241
161
|
return new ChatClientAgent(
|
|
242
162
|
chatClient,
|
|
243
163
|
name: key,
|
|
244
|
-
instructions: "You are an order analysis expert."
|
|
245
|
-
tools:
|
|
246
|
-
[
|
|
247
|
-
AIFunctionFactory.Create(orderFunctions.GetOrderAsync),
|
|
248
|
-
AIFunctionFactory.Create(orderFunctions.CalculateDiscountAsync)
|
|
249
|
-
]);
|
|
164
|
+
instructions: "You are an order analysis expert.");
|
|
250
165
|
});
|
|
251
|
-
|
|
252
|
-
// Simple agent (no tools)
|
|
253
|
-
builder.AddAIAgent(
|
|
254
|
-
name: "Editor",
|
|
255
|
-
instructions: "You are an editor who improves text quality.");
|
|
256
166
|
```
|
|
257
167
|
|
|
258
|
-
|
|
168
|
+
Inject by key:
|
|
259
169
|
|
|
260
170
|
```csharp
|
|
261
|
-
// Controller
|
|
262
171
|
public class AgentController(
|
|
263
|
-
[FromKeyedServices("OrderAnalyzer")] AIAgent orderAgent) : ControllerBase
|
|
264
|
-
{
|
|
265
|
-
[HttpPost("analyze")]
|
|
266
|
-
public async Task<IActionResult> Analyze(OrderRequest request)
|
|
267
|
-
{
|
|
268
|
-
var response = await orderAgent.RunAsync(request.Prompt);
|
|
269
|
-
return Ok(response.Text);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// Blazor component
|
|
274
|
-
@inject IServiceProvider ServiceProvider
|
|
275
|
-
@code {
|
|
276
|
-
private AIAgent _agent = default!;
|
|
277
|
-
|
|
278
|
-
protected override void OnInitialized()
|
|
279
|
-
{
|
|
280
|
-
_agent = ServiceProvider.GetRequiredKeyedService<AIAgent>("OrderAnalyzer");
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
---
|
|
286
|
-
|
|
287
|
-
## Streaming
|
|
288
|
-
|
|
289
|
-
```csharp
|
|
290
|
-
await foreach (var update in agent.RunStreamingAsync(
|
|
291
|
-
"Write a detailed analysis.",
|
|
292
|
-
cancellationToken: ct))
|
|
293
|
-
{
|
|
294
|
-
if (update is AgentResponseUpdateEvent e)
|
|
295
|
-
{
|
|
296
|
-
Console.Write(e.Data);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
172
|
+
[FromKeyedServices("OrderAnalyzer")] AIAgent orderAgent) : ControllerBase { ... }
|
|
299
173
|
```
|
|
300
174
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
## Recommended Models
|
|
304
|
-
|
|
305
|
-
| Use Case | Model | Provider | Cost (per 1M input tokens) |
|
|
306
|
-
|----------|-------|----------|---------------------------|
|
|
307
|
-
| Simple tasks (default) | gpt-4o-mini | Azure OpenAI | $0.15 |
|
|
308
|
-
| Complex analysis | gpt-4o | Azure OpenAI | $2.50 |
|
|
309
|
-
| Embeddings | text-embedding-3-small | Azure OpenAI | $0.02 |
|
|
310
|
-
| Local development | llama3.2:3b | Ollama | Free |
|
|
311
|
-
| Cloud development | gpt-4o-mini | GitHub Models | Free (preview) |
|
|
312
|
-
|
|
313
|
-
**MORPH-SPEC default:** `gpt-4o-mini` for production.
|
|
175
|
+
For agents with tools and structured output, see `ai-agents-multi-agent-patterns` and `ai-agents-structured-output` (Onda 2).
|
|
314
176
|
|
|
315
177
|
---
|
|
316
178
|
|
|
317
|
-
##
|
|
318
|
-
|
|
319
|
-
### API Keys in Azure Key Vault
|
|
179
|
+
## 5. OpenTelemetry
|
|
320
180
|
|
|
321
181
|
```csharp
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
builder.Configuration.AddAzureKeyVault(keyVaultUri, new DefaultAzureCredential());
|
|
326
|
-
}
|
|
327
|
-
```
|
|
182
|
+
using OpenTelemetry;
|
|
183
|
+
using OpenTelemetry.Trace;
|
|
184
|
+
using Microsoft.Agents.AI;
|
|
328
185
|
|
|
329
|
-
|
|
186
|
+
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
|
|
187
|
+
.AddSource(AgentOpenTelemetryConsts.DefaultSourceName)
|
|
188
|
+
.AddOtlpExporter()
|
|
189
|
+
.Build();
|
|
330
190
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
// AzureCliCredential in development
|
|
334
|
-
var client = new AzureOpenAIClient(
|
|
335
|
-
new Uri(config["AzureOpenAI:Endpoint"]!),
|
|
336
|
-
new DefaultAzureCredential());
|
|
191
|
+
// Wrap any agent (e.g. the `agent` from §2)
|
|
192
|
+
var instrumented = agent.WithOpenTelemetry();
|
|
337
193
|
```
|
|
338
194
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
## Observability
|
|
342
|
-
|
|
343
|
-
```csharp
|
|
344
|
-
// Enable OpenTelemetry on agents
|
|
345
|
-
agent.WithOpenTelemetry();
|
|
346
|
-
|
|
347
|
-
// Program.cs — Aspire Dashboard integration
|
|
348
|
-
builder.Services.AddOpenTelemetry()
|
|
349
|
-
.WithTracing(tracing =>
|
|
350
|
-
{
|
|
351
|
-
tracing.AddSource("Experimental.Microsoft.Extensions.AI.*");
|
|
352
|
-
tracing.AddAspNetCoreInstrumentation();
|
|
353
|
-
})
|
|
354
|
-
.WithMetrics(metrics =>
|
|
355
|
-
{
|
|
356
|
-
metrics.AddMeter("Experimental.Microsoft.Extensions.AI.*");
|
|
357
|
-
metrics.AddAspNetCoreInstrumentation();
|
|
358
|
-
});
|
|
359
|
-
```
|
|
195
|
+
> **Note:** Source name is `AgentOpenTelemetryConsts.DefaultSourceName` from `Microsoft.Agents.AI`. **Do NOT** use the old `Experimental.Microsoft.Extensions.AI.*` source — it belongs to a previous package family.
|
|
360
196
|
|
|
361
197
|
---
|
|
362
198
|
|
|
363
|
-
##
|
|
199
|
+
## 6. Security checklist
|
|
364
200
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
| Tools not invoked | Missing `[Description]` | Add `[Description]` to method AND parameters |
|
|
370
|
-
| Agent returns empty | No instructions | Always set `Instructions` in agent options |
|
|
201
|
+
- [ ] API keys never in source. Bind from environment variables / secret store (the VPS deploy uses env vars; Docker secrets or a vault are fine too).
|
|
202
|
+
- [ ] `appsettings.json` checked into git never contains real keys — only placeholder/empty values.
|
|
203
|
+
- [ ] Provider keys (`OpenAI:ApiKey`, `Google:ApiKey`, `Anthropic:ApiKey`) bound from environment.
|
|
204
|
+
- [ ] No agent receives raw user input without input-validation middleware (see `ai-agents-middleware-patterns` — Onda 2).
|
|
371
205
|
|
|
372
206
|
---
|
|
373
207
|
|
|
374
|
-
##
|
|
208
|
+
## 7. What NOT to do (anti-patterns)
|
|
375
209
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
- [ ] Error handling via middleware (see `production.md`)
|
|
210
|
+
| Wrong | Right |
|
|
211
|
+
|-------|-------|
|
|
212
|
+
| `using Microsoft.SemanticKernel` | `using Microsoft.Agents.AI` |
|
|
213
|
+
| `Kernel.InvokePromptAsync()` | `agent.RunAsync()` |
|
|
214
|
+
| `[KernelFunction]` | `[Description]` on method + parameters; register via `AIFunctionFactory.Create()` |
|
|
215
|
+
| `ChatHistory` | `IEnumerable<ChatMessage>` |
|
|
216
|
+
| Hardcoded model strings spread across codebase | Single source via Model Registry (see `ai-agents-providers-model-registry`) |
|
|
217
|
+
| `Microsoft.Extensions.AI.OpenAI` 9.* | `Microsoft.Agents.AI.OpenAI` 1.* GA |
|
|
218
|
+
| Hosted agent service "to simplify" | Direct models always |
|
|
386
219
|
|
|
387
220
|
---
|
|
388
221
|
|
|
389
|
-
##
|
|
222
|
+
## 8. Checklist (verifiable by morph-eval)
|
|
390
223
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
| `AgentTool.FromMethod()` | `AIFunctionFactory.Create(method)` |
|
|
398
|
-
| `_chatClient.CreateAgent()` | `new ChatClientAgent()` or `.AsAIAgent()` |
|
|
399
|
-
| `agent.CreateThreadAsync()` | Use session/conversation management |
|
|
400
|
-
| `ChatHistory` | `IEnumerable<ChatMessage>` |
|
|
401
|
-
| Hardcoded API keys | Key Vault / Managed Identity |
|
|
402
|
-
| Models < 3B for tools | gpt-4o-mini minimum |
|
|
224
|
+
- [ ] `Microsoft.Agents.AI` package present in `.csproj`
|
|
225
|
+
- [ ] No `Microsoft.SemanticKernel.*` references
|
|
226
|
+
- [ ] `IChatClient` registered (either directly or via Model Registry)
|
|
227
|
+
- [ ] At least one `AIAgent` created via `AsAIAgent()` or `new ChatClientAgent()`
|
|
228
|
+
- [ ] OpenTelemetry source name is `AgentOpenTelemetryConsts.DefaultSourceName` (if telemetry wired)
|
|
229
|
+
- [ ] Models reference Model Registry alias when project has >1 model use case
|
|
403
230
|
|
|
404
231
|
---
|
|
405
232
|
|
|
406
|
-
## References
|
|
233
|
+
## 9. References
|
|
407
234
|
|
|
408
|
-
-
|
|
409
|
-
-
|
|
410
|
-
-
|
|
411
|
-
-
|
|
412
|
-
-
|
|
413
|
-
-
|
|
414
|
-
- `blazor-ui.md` — Natural Language First UI patterns
|
|
235
|
+
- `ai-agents-sweet-spot` — when to use agents vs workflows
|
|
236
|
+
- `ai-agents-providers-model-registry` — provider-agnostic pattern
|
|
237
|
+
- `ai-agents-structured-output` (Onda 2) — typed responses
|
|
238
|
+
- `ai-agents-middleware-patterns` (Onda 2) — telemetry, retry, anti-hallucination, streaming agent responses
|
|
239
|
+
- Microsoft.Agents.AI docs: https://learn.microsoft.com/agent-framework/
|
|
240
|
+
- Verified packages list (context7 /microsoft/agent-framework): retrieved 2026-05-19
|
|
415
241
|
|
|
416
242
|
---
|
|
417
243
|
|
|
418
|
-
*MORPH-SPEC by Polymorphism Tech*
|
|
244
|
+
*MORPH-SPEC by Polymorphism Tech — ai-agents/setup.md v2.0 (2026-05-19)*
|