@polymorphism-tech/morph-spec 1.0.2 → 2.0.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/CLAUDE.md +1381 -0
- package/LICENSE +72 -0
- package/README.md +114 -12
- package/bin/detect-agents.js +225 -0
- package/bin/morph-spec.js +120 -0
- package/bin/render-template.js +302 -0
- package/bin/semantic-detect-agents.js +246 -0
- package/bin/validate-agents-skills.js +239 -0
- package/bin/validate-agents.js +69 -0
- package/bin/validate-phase.js +263 -0
- package/content/.azure/README.md +293 -0
- package/content/.azure/docs/azure-devops-setup.md +454 -0
- package/content/.azure/docs/branch-strategy.md +398 -0
- package/content/.azure/docs/local-development.md +515 -0
- package/content/.azure/pipelines/pipeline-variables.yml +34 -0
- package/content/.azure/pipelines/prod-pipeline.yml +319 -0
- package/content/.azure/pipelines/staging-pipeline.yml +234 -0
- package/content/.azure/pipelines/templates/build-dotnet.yml +75 -0
- package/content/.azure/pipelines/templates/deploy-app-service.yml +94 -0
- package/content/.azure/pipelines/templates/deploy-container-app.yml +120 -0
- package/content/.azure/pipelines/templates/infra-deploy.yml +90 -0
- package/content/.claude/commands/morph-apply.md +118 -26
- package/content/.claude/commands/morph-archive.md +9 -9
- package/content/.claude/commands/morph-clarify.md +184 -0
- package/content/.claude/commands/morph-design.md +275 -0
- package/content/.claude/commands/morph-proposal.md +56 -15
- package/content/.claude/commands/morph-setup.md +100 -0
- package/content/.claude/commands/morph-status.md +47 -32
- package/content/.claude/commands/morph-tasks.md +319 -0
- package/content/.claude/commands/morph-uiux.md +211 -0
- package/content/.claude/skills/specialists/ai-system-architect.md +604 -0
- package/content/.claude/skills/specialists/ms-agent-expert.md +143 -89
- package/content/.claude/skills/specialists/ui-ux-designer.md +744 -9
- package/content/.claude/skills/stacks/dotnet-blazor.md +244 -8
- package/content/.claude/skills/stacks/dotnet-nextjs.md +2 -2
- package/content/.morph/.morphversion +5 -0
- package/content/.morph/config/agents.json +101 -8
- package/content/.morph/config/azure-pricing.json +70 -0
- package/content/.morph/config/azure-pricing.schema.json +50 -0
- package/content/.morph/config/config.template.json +15 -3
- package/content/.morph/docs/STORY-DRIVEN-DEVELOPMENT.md +392 -0
- package/content/.morph/hooks/README.md +239 -0
- package/content/.morph/hooks/pre-commit-agents.sh +24 -0
- package/content/.morph/hooks/pre-commit-all.sh +48 -0
- package/content/.morph/hooks/pre-commit-costs.sh +91 -0
- package/content/.morph/hooks/pre-commit-specs.sh +49 -0
- package/content/.morph/hooks/pre-commit-tests.sh +60 -0
- package/content/.morph/project.md +5 -4
- package/content/.morph/schemas/agent.schema.json +296 -0
- package/content/.morph/standards/agent-framework-setup.md +453 -0
- package/content/.morph/standards/architecture.md +142 -7
- package/content/.morph/standards/azure.md +218 -23
- package/content/.morph/standards/coding.md +47 -12
- package/content/.morph/standards/dotnet10-migration.md +494 -0
- package/content/.morph/standards/fluent-ui-setup.md +590 -0
- package/content/.morph/standards/migration-guide.md +514 -0
- package/content/.morph/standards/passkeys-auth.md +423 -0
- package/content/.morph/standards/vector-search-rag.md +536 -0
- package/content/.morph/state.json +18 -0
- package/content/.morph/templates/FluentDesignTheme.cs +149 -0
- package/content/.morph/templates/MudTheme.cs +281 -0
- package/content/.morph/templates/contracts.cs +55 -55
- package/content/.morph/templates/decisions.md +4 -4
- package/content/.morph/templates/design-system.css +226 -0
- package/content/.morph/templates/infra/.dockerignore.example +89 -0
- package/content/.morph/templates/infra/Dockerfile.example +82 -0
- package/content/.morph/templates/infra/README.md +286 -0
- package/content/.morph/templates/infra/app-service.bicep +164 -0
- package/content/.morph/templates/infra/deploy.ps1 +229 -0
- package/content/.morph/templates/infra/deploy.sh +208 -0
- package/content/.morph/templates/infra/main.bicep +41 -7
- package/content/.morph/templates/infra/parameters.dev.json +6 -0
- package/content/.morph/templates/infra/parameters.prod.json +6 -0
- package/content/.morph/templates/infra/parameters.staging.json +29 -0
- package/content/.morph/templates/proposal.md +3 -3
- package/content/.morph/templates/recap.md +3 -3
- package/content/.morph/templates/spec.md +9 -8
- package/content/.morph/templates/sprint-status.yaml +68 -0
- package/content/.morph/templates/state.template.json +222 -0
- package/content/.morph/templates/story.md +143 -0
- package/content/.morph/templates/tasks.md +1 -1
- package/content/.morph/templates/ui-components.md +276 -0
- package/content/.morph/templates/ui-design-system.md +286 -0
- package/content/.morph/templates/ui-flows.md +336 -0
- package/content/.morph/templates/ui-mockups.md +133 -0
- package/content/.morph/test-infra/example.bicep +59 -0
- package/content/CLAUDE.md +124 -0
- package/content/README.md +79 -0
- package/detectors/config-detector.js +223 -0
- package/detectors/conversation-analyzer.js +163 -0
- package/detectors/index.js +84 -0
- package/detectors/standards-generator.js +275 -0
- package/detectors/structure-detector.js +221 -0
- package/docs/README.md +149 -0
- package/docs/api/cost-calculator.js.html +513 -0
- package/docs/api/design-system-generator.js.html +382 -0
- package/docs/api/fonts/Montserrat/Montserrat-Bold.eot +0 -0
- package/docs/api/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
- package/docs/api/fonts/Montserrat/Montserrat-Bold.woff +0 -0
- package/docs/api/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
- package/docs/api/fonts/Montserrat/Montserrat-Regular.eot +0 -0
- package/docs/api/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
- package/docs/api/fonts/Montserrat/Montserrat-Regular.woff +0 -0
- package/docs/api/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
- package/docs/api/global.html +5263 -0
- package/docs/api/index.html +96 -0
- package/docs/api/scripts/collapse.js +39 -0
- package/docs/api/scripts/commonNav.js +28 -0
- package/docs/api/scripts/linenumber.js +25 -0
- package/docs/api/scripts/nav.js +12 -0
- package/docs/api/scripts/polyfill.js +4 -0
- package/docs/api/scripts/prettify/Apache-License-2.0.txt +202 -0
- package/docs/api/scripts/prettify/lang-css.js +2 -0
- package/docs/api/scripts/prettify/prettify.js +28 -0
- package/docs/api/scripts/search.js +99 -0
- package/docs/api/state-manager.js.html +423 -0
- package/docs/api/styles/jsdoc.css +776 -0
- package/docs/api/styles/prettify.css +80 -0
- package/docs/examples.md +328 -0
- package/docs/getting-started.md +302 -0
- package/docs/installation.md +361 -0
- package/docs/templates.md +418 -0
- package/docs/validation-checklist.md +266 -0
- package/package.json +39 -12
- package/src/commands/cost.js +181 -0
- package/src/commands/create-story.js +283 -0
- package/src/commands/detect.js +104 -0
- package/src/commands/doctor.js +67 -0
- package/src/commands/generate.js +149 -0
- package/src/commands/init.js +71 -46
- package/src/commands/shard-spec.js +224 -0
- package/src/commands/sprint-status.js +250 -0
- package/src/commands/state.js +333 -0
- package/src/commands/sync.js +167 -0
- package/src/commands/update-pricing.js +206 -0
- package/src/commands/update.js +88 -13
- package/src/lib/complexity-analyzer.js +292 -0
- package/src/lib/cost-calculator.js +429 -0
- package/src/lib/design-system-generator.js +298 -0
- package/src/lib/state-manager.js +340 -0
- package/src/utils/file-copier.js +63 -0
- package/src/utils/version-checker.js +175 -0
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
# Microsoft Agent Framework - Setup Obrigatório (.NET 10)
|
|
2
|
+
|
|
3
|
+
> **IMPORTANTE:** O MORPH-SPEC usa **exclusivamente** o Microsoft Agent Framework.
|
|
4
|
+
> Semantic Kernel foi descontinuado. Não use mais.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 📦 Packages Necessários
|
|
9
|
+
|
|
10
|
+
```xml
|
|
11
|
+
<!-- .csproj -->
|
|
12
|
+
<PackageReference Include="Microsoft.Agents.AI" Version="1.0.0" />
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**Nota:** O package `Microsoft.Agents.AI` já traz as dependências:
|
|
16
|
+
- `Microsoft.Extensions.AI`
|
|
17
|
+
- `OpenAI` (cliente)
|
|
18
|
+
- Suporte a múltiplos providers (Azure OpenAI, GitHub Models, Ollama)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## ⚙️ Configuração no Program.cs
|
|
23
|
+
|
|
24
|
+
### 1. Registrar ChatClient (Azure OpenAI)
|
|
25
|
+
|
|
26
|
+
```csharp
|
|
27
|
+
using Microsoft.Extensions.AI;
|
|
28
|
+
|
|
29
|
+
var builder = WebApplication.CreateBuilder(args);
|
|
30
|
+
|
|
31
|
+
// Registrar ChatClient como singleton
|
|
32
|
+
builder.Services.AddSingleton<IChatClient>(sp =>
|
|
33
|
+
{
|
|
34
|
+
var config = sp.GetRequiredService<IConfiguration>();
|
|
35
|
+
|
|
36
|
+
return new ChatClient(
|
|
37
|
+
model: "gpt-4o-mini", // Modelo padrão para tasks simples
|
|
38
|
+
credential: new ApiKeyCredential(config["AzureOpenAI:ApiKey"]!),
|
|
39
|
+
endpoint: new Uri(config["AzureOpenAI:Endpoint"]!)
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. Registrar ChatClient (GitHub Models - Desenvolvimento)
|
|
45
|
+
|
|
46
|
+
```csharp
|
|
47
|
+
builder.Services.AddSingleton<IChatClient>(sp =>
|
|
48
|
+
{
|
|
49
|
+
var config = sp.GetRequiredService<IConfiguration>();
|
|
50
|
+
|
|
51
|
+
return new ChatClient(
|
|
52
|
+
model: "gpt-4.1-mini",
|
|
53
|
+
credential: new ApiKeyCredential(config["GitHub:Token"]!),
|
|
54
|
+
endpoint: new Uri("https://models.github.com")
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 3. Registrar ChatClient (Ollama - Local)
|
|
60
|
+
|
|
61
|
+
```csharp
|
|
62
|
+
builder.Services.AddSingleton<IChatClient>(sp =>
|
|
63
|
+
{
|
|
64
|
+
return new ChatClient(
|
|
65
|
+
model: "llama3.2:3b",
|
|
66
|
+
endpoint: new Uri("http://localhost:11434")
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Escolha o provider adequado ao ambiente.**
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 🤖 Pattern de Agent (Obrigatório)
|
|
76
|
+
|
|
77
|
+
### Interface do Agent
|
|
78
|
+
|
|
79
|
+
```csharp
|
|
80
|
+
public interface IOrderAnalysisAgent
|
|
81
|
+
{
|
|
82
|
+
Task<string> AnalyzeAsync(Order order, CancellationToken ct = default);
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Implementação do Agent
|
|
87
|
+
|
|
88
|
+
```csharp
|
|
89
|
+
using Microsoft.Agents.AI;
|
|
90
|
+
|
|
91
|
+
public class OrderAnalysisAgent : IOrderAnalysisAgent
|
|
92
|
+
{
|
|
93
|
+
private readonly IChatClient _chatClient;
|
|
94
|
+
private readonly ILogger<OrderAnalysisAgent> _logger;
|
|
95
|
+
|
|
96
|
+
public OrderAnalysisAgent(
|
|
97
|
+
IChatClient chatClient,
|
|
98
|
+
ILogger<OrderAnalysisAgent> logger)
|
|
99
|
+
{
|
|
100
|
+
_chatClient = chatClient;
|
|
101
|
+
_logger = logger;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public async Task<string> AnalyzeAsync(Order order, CancellationToken ct = default)
|
|
105
|
+
{
|
|
106
|
+
// Criar agente com instruções específicas
|
|
107
|
+
var agent = _chatClient.CreateAgent(
|
|
108
|
+
instructions: """
|
|
109
|
+
Você é um especialista em análise de pedidos de e-commerce.
|
|
110
|
+
|
|
111
|
+
Analise o pedido fornecido e retorne:
|
|
112
|
+
1. Resumo do pedido
|
|
113
|
+
2. Sugestões de upsell baseadas nos itens
|
|
114
|
+
3. Risco de cancelamento (baixo/médio/alto) com justificativa
|
|
115
|
+
|
|
116
|
+
Seja conciso e objetivo.
|
|
117
|
+
""",
|
|
118
|
+
name: "OrderAnalyzer"
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
// Criar prompt com dados do pedido
|
|
122
|
+
var prompt = $"""
|
|
123
|
+
Pedido: {order.OrderNumber}
|
|
124
|
+
Total: {order.Total:C}
|
|
125
|
+
Itens: {order.Items.Count}
|
|
126
|
+
Cliente: {order.Customer.Name}
|
|
127
|
+
Histórico: {order.Customer.TotalOrders} pedidos anteriores
|
|
128
|
+
|
|
129
|
+
Analise este pedido.
|
|
130
|
+
""";
|
|
131
|
+
|
|
132
|
+
_logger.LogInformation("Analisando pedido {OrderNumber}", order.OrderNumber);
|
|
133
|
+
|
|
134
|
+
// Executar agente
|
|
135
|
+
var response = await agent.RunAsync(prompt, cancellationToken: ct);
|
|
136
|
+
|
|
137
|
+
return response.Content;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Registrar Agent como Service
|
|
143
|
+
|
|
144
|
+
```csharp
|
|
145
|
+
// Program.cs
|
|
146
|
+
builder.Services.AddScoped<IOrderAnalysisAgent, OrderAnalysisAgent>();
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 🔧 Agents com Tools (Function Calling)
|
|
152
|
+
|
|
153
|
+
### Definir Tools
|
|
154
|
+
|
|
155
|
+
```csharp
|
|
156
|
+
public class WeatherAgent
|
|
157
|
+
{
|
|
158
|
+
private readonly IChatClient _chatClient;
|
|
159
|
+
private readonly IWeatherService _weatherService;
|
|
160
|
+
|
|
161
|
+
public WeatherAgent(IChatClient chatClient, IWeatherService weatherService)
|
|
162
|
+
{
|
|
163
|
+
_chatClient = chatClient;
|
|
164
|
+
_weatherService = weatherService;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Tool 1: Buscar clima
|
|
168
|
+
[AgentTool("get_weather")]
|
|
169
|
+
[Description("Busca o clima atual de uma cidade")]
|
|
170
|
+
public async Task<string> GetWeatherAsync(
|
|
171
|
+
[Description("Nome da cidade")] string city,
|
|
172
|
+
CancellationToken ct = default)
|
|
173
|
+
{
|
|
174
|
+
var weather = await _weatherService.GetCurrentWeatherAsync(city, ct);
|
|
175
|
+
return $"Temp: {weather.Temperature}°C, Condição: {weather.Condition}";
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Tool 2: Previsão
|
|
179
|
+
[AgentTool("get_forecast")]
|
|
180
|
+
[Description("Busca a previsão para os próximos dias")]
|
|
181
|
+
public async Task<string> GetForecastAsync(
|
|
182
|
+
[Description("Nome da cidade")] string city,
|
|
183
|
+
[Description("Número de dias")] int days = 3,
|
|
184
|
+
CancellationToken ct = default)
|
|
185
|
+
{
|
|
186
|
+
var forecast = await _weatherService.GetForecastAsync(city, days, ct);
|
|
187
|
+
return string.Join("\n", forecast.Select(f => $"{f.Date:dd/MM}: {f.Temperature}°C"));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
public async Task<string> ChatAsync(string userMessage, CancellationToken ct = default)
|
|
191
|
+
{
|
|
192
|
+
// Criar agente com tools
|
|
193
|
+
var agent = _chatClient.CreateAgent(
|
|
194
|
+
instructions: """
|
|
195
|
+
Você é um assistente de clima.
|
|
196
|
+
Use as tools disponíveis para responder perguntas sobre o tempo.
|
|
197
|
+
Seja amigável e informativo.
|
|
198
|
+
""",
|
|
199
|
+
name: "WeatherAssistant",
|
|
200
|
+
tools: new[]
|
|
201
|
+
{
|
|
202
|
+
AgentTool.FromMethod(nameof(GetWeatherAsync), this),
|
|
203
|
+
AgentTool.FromMethod(nameof(GetForecastAsync), this)
|
|
204
|
+
}
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
var response = await agent.RunAsync(userMessage, cancellationToken: ct);
|
|
208
|
+
return response.Content;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**Nota:** Cada método com `[AgentTool]` vira uma tool que o agente pode chamar automaticamente.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## 💬 Threads (Persistência de Conversação)
|
|
218
|
+
|
|
219
|
+
### Criar e Usar Thread
|
|
220
|
+
|
|
221
|
+
```csharp
|
|
222
|
+
public class ChatService
|
|
223
|
+
{
|
|
224
|
+
private readonly IChatClient _chatClient;
|
|
225
|
+
private readonly Dictionary<string, AgentThread> _threads = new();
|
|
226
|
+
|
|
227
|
+
public async Task<string> StartConversationAsync(string userId)
|
|
228
|
+
{
|
|
229
|
+
var agent = _chatClient.CreateAgent(
|
|
230
|
+
instructions: "Você é um assistente útil e amigável.",
|
|
231
|
+
name: "ChatAssistant"
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
// Criar thread
|
|
235
|
+
var thread = await agent.CreateThreadAsync();
|
|
236
|
+
|
|
237
|
+
// Armazenar thread ID para o usuário
|
|
238
|
+
_threads[userId] = thread;
|
|
239
|
+
|
|
240
|
+
return thread.Id;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
public async Task<string> SendMessageAsync(
|
|
244
|
+
string userId,
|
|
245
|
+
string message,
|
|
246
|
+
CancellationToken ct = default)
|
|
247
|
+
{
|
|
248
|
+
if (!_threads.TryGetValue(userId, out var thread))
|
|
249
|
+
throw new InvalidOperationException("Thread não encontrada");
|
|
250
|
+
|
|
251
|
+
var agent = _chatClient.CreateAgent(
|
|
252
|
+
instructions: "Você é um assistente útil e amigável.",
|
|
253
|
+
name: "ChatAssistant"
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
// Adicionar mensagem do usuário
|
|
257
|
+
await thread.AddMessageAsync(message, ct);
|
|
258
|
+
|
|
259
|
+
// Executar agente no contexto do thread
|
|
260
|
+
var response = await agent.RunAsync(thread, cancellationToken: ct);
|
|
261
|
+
|
|
262
|
+
// Histórico é mantido automaticamente
|
|
263
|
+
return response.Content;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
**Vantagem:** Threads mantêm todo o histórico da conversa automaticamente.
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## 🔄 Multi-Agent Communication (A2A)
|
|
273
|
+
|
|
274
|
+
### Agent-to-Agent Pattern
|
|
275
|
+
|
|
276
|
+
```csharp
|
|
277
|
+
public class ResearchAgent
|
|
278
|
+
{
|
|
279
|
+
private readonly IChatClient _chatClient;
|
|
280
|
+
|
|
281
|
+
public async Task<string> ResearchTopicAsync(string topic)
|
|
282
|
+
{
|
|
283
|
+
// Agent 1: Researcher
|
|
284
|
+
var researcher = _chatClient.CreateAgent(
|
|
285
|
+
instructions: "Você pesquisa tópicos e fornece informações detalhadas.",
|
|
286
|
+
name: "Researcher"
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
// Agent 2: Summarizer
|
|
290
|
+
var summarizer = _chatClient.CreateAgent(
|
|
291
|
+
instructions: "Você resume textos longos de forma concisa.",
|
|
292
|
+
name: "Summarizer"
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
// Passo 1: Pesquisar
|
|
296
|
+
var research = await researcher.RunAsync($"Pesquise sobre: {topic}");
|
|
297
|
+
|
|
298
|
+
// Passo 2: Resumir resultado da pesquisa
|
|
299
|
+
var summary = await summarizer.RunAsync(
|
|
300
|
+
$"Resuma o seguinte texto:\n\n{research.Content}"
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
return summary.Content;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## 📊 Modelos Recomendados
|
|
311
|
+
|
|
312
|
+
| Uso | Modelo | Provider | Custo |
|
|
313
|
+
|-----|--------|----------|-------|
|
|
314
|
+
| Tarefas simples | gpt-4o-mini | Azure OpenAI | $0.15/1M input |
|
|
315
|
+
| Análise complexa | gpt-4o | Azure OpenAI | $2.50/1M input |
|
|
316
|
+
| Desenvolvimento local | llama3.2:3b | Ollama | Grátis |
|
|
317
|
+
| Desenvolvimento cloud | gpt-4.1-mini | GitHub Models | Grátis (beta) |
|
|
318
|
+
|
|
319
|
+
**Padrão MORPH-SPEC:** `gpt-4o-mini` para produção.
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## 🔐 Segurança
|
|
324
|
+
|
|
325
|
+
### API Keys no Azure Key Vault
|
|
326
|
+
|
|
327
|
+
```csharp
|
|
328
|
+
// Program.cs
|
|
329
|
+
if (builder.Environment.IsProduction())
|
|
330
|
+
{
|
|
331
|
+
var keyVaultUri = new Uri(builder.Configuration["KeyVault:Uri"]!);
|
|
332
|
+
builder.Configuration.AddAzureKeyVault(keyVaultUri, new DefaultAzureCredential());
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
builder.Services.AddSingleton<IChatClient>(sp =>
|
|
336
|
+
{
|
|
337
|
+
var config = sp.GetRequiredService<IConfiguration>();
|
|
338
|
+
|
|
339
|
+
// API Key vem do Key Vault em produção
|
|
340
|
+
var apiKey = config["AzureOpenAI:ApiKey"]!;
|
|
341
|
+
var endpoint = config["AzureOpenAI:Endpoint"]!;
|
|
342
|
+
|
|
343
|
+
return new ChatClient(
|
|
344
|
+
model: "gpt-4o-mini",
|
|
345
|
+
credential: new ApiKeyCredential(apiKey),
|
|
346
|
+
endpoint: new Uri(endpoint)
|
|
347
|
+
);
|
|
348
|
+
});
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### Managed Identity (Recomendado)
|
|
352
|
+
|
|
353
|
+
```csharp
|
|
354
|
+
builder.Services.AddSingleton<IChatClient>(sp =>
|
|
355
|
+
{
|
|
356
|
+
var config = sp.GetRequiredService<IConfiguration>();
|
|
357
|
+
var endpoint = config["AzureOpenAI:Endpoint"]!;
|
|
358
|
+
|
|
359
|
+
return new ChatClient(
|
|
360
|
+
model: "gpt-4o-mini",
|
|
361
|
+
credential: new DefaultAzureCredential(), // Managed Identity
|
|
362
|
+
endpoint: new Uri(endpoint)
|
|
363
|
+
);
|
|
364
|
+
});
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## 📈 Observabilidade com .NET Aspire
|
|
370
|
+
|
|
371
|
+
### Integrar com Aspire Dashboard
|
|
372
|
+
|
|
373
|
+
```csharp
|
|
374
|
+
// Program.cs
|
|
375
|
+
builder.Services.AddOpenTelemetry()
|
|
376
|
+
.WithTracing(tracing =>
|
|
377
|
+
{
|
|
378
|
+
tracing.AddSource("Microsoft.Agents.AI");
|
|
379
|
+
tracing.AddAspireTracing();
|
|
380
|
+
})
|
|
381
|
+
.WithMetrics(metrics =>
|
|
382
|
+
{
|
|
383
|
+
metrics.AddMeter("Microsoft.Agents.AI");
|
|
384
|
+
metrics.AddAspireMetrics();
|
|
385
|
+
});
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
**Resultado:** Visualize chamadas a agentes e tools no Aspire Dashboard.
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## ⚠️ Limitações e Troubleshooting
|
|
393
|
+
|
|
394
|
+
### Tool Calling com Modelos Pequenos
|
|
395
|
+
|
|
396
|
+
**Problema:** Modelos abaixo de 3B parâmetros não fazem tool calling bem.
|
|
397
|
+
|
|
398
|
+
**Solução:** Use `gpt-4o-mini` (mínimo) para agents com tools.
|
|
399
|
+
|
|
400
|
+
### Rate Limits
|
|
401
|
+
|
|
402
|
+
```csharp
|
|
403
|
+
public async Task<string> AnalyzeWithRetryAsync(Order order, CancellationToken ct = default)
|
|
404
|
+
{
|
|
405
|
+
var retryPolicy = Policy
|
|
406
|
+
.Handle<RateLimitException>()
|
|
407
|
+
.WaitAndRetryAsync(3, attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)));
|
|
408
|
+
|
|
409
|
+
return await retryPolicy.ExecuteAsync(async () =>
|
|
410
|
+
{
|
|
411
|
+
var agent = _chatClient.CreateAgent(...);
|
|
412
|
+
var response = await agent.RunAsync(..., cancellationToken: ct);
|
|
413
|
+
return response.Content;
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
## ✅ Checklist de Implementação
|
|
421
|
+
|
|
422
|
+
- [ ] Package `Microsoft.Agents.AI` instalado
|
|
423
|
+
- [ ] `IChatClient` registrado como singleton
|
|
424
|
+
- [ ] Agents criados com `client.CreateAgent()`
|
|
425
|
+
- [ ] Agents registrados como services (scoped/transient)
|
|
426
|
+
- [ ] API keys no Key Vault (produção)
|
|
427
|
+
- [ ] Logging configurado para agents
|
|
428
|
+
- [ ] Observabilidade com Aspire (opcional)
|
|
429
|
+
- [ ] Error handling para rate limits
|
|
430
|
+
- [ ] Testes de integração para agents
|
|
431
|
+
|
|
432
|
+
---
|
|
433
|
+
|
|
434
|
+
## 🚫 O Que NÃO Fazer
|
|
435
|
+
|
|
436
|
+
❌ Usar Semantic Kernel
|
|
437
|
+
❌ Usar `Kernel.CreateFunctionFromPrompt()`
|
|
438
|
+
❌ Usar `ChatHistory` (use Threads)
|
|
439
|
+
❌ Hardcoded API keys
|
|
440
|
+
❌ Modelos pequenos (<3B) para tool calling
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## 📚 Referências
|
|
445
|
+
|
|
446
|
+
- [Microsoft Agent Framework Documentation](https://learn.microsoft.com/agent-framework/)
|
|
447
|
+
- [Agent Framework GitHub](https://github.com/microsoft/agent-framework)
|
|
448
|
+
- [Microsoft.Extensions.AI](https://learn.microsoft.com/dotnet/ai/ai-extensions)
|
|
449
|
+
- [Azure OpenAI Service](https://learn.microsoft.com/azure/ai-services/openai/)
|
|
450
|
+
|
|
451
|
+
---
|
|
452
|
+
|
|
453
|
+
*MORPH-SPEC by Polymorphism Tech*
|
|
@@ -147,19 +147,29 @@ services.AddHttpClient<IMemberKitClient, MemberKitClient>(client =>
|
|
|
147
147
|
|
|
148
148
|
---
|
|
149
149
|
|
|
150
|
-
## 🤖 Agents como Services
|
|
150
|
+
## 🤖 Agents como Services (.NET 10)
|
|
151
|
+
|
|
152
|
+
> **IMPORTANTE:** Use exclusivamente Microsoft Agent Framework.
|
|
151
153
|
|
|
152
154
|
```csharp
|
|
153
155
|
// Agents/DependencyInjection.cs
|
|
156
|
+
using Microsoft.Extensions.AI;
|
|
157
|
+
|
|
154
158
|
public static IServiceCollection AddAgents(this IServiceCollection services, IConfiguration configuration)
|
|
155
159
|
{
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
apiKey: configuration["AzureOpenAI:ApiKey"]!);
|
|
160
|
+
// Registrar ChatClient
|
|
161
|
+
services.AddSingleton<IChatClient>(sp =>
|
|
162
|
+
{
|
|
163
|
+
var config = sp.GetRequiredService<IConfiguration>();
|
|
161
164
|
|
|
162
|
-
|
|
165
|
+
return new ChatClient(
|
|
166
|
+
model: "gpt-4o-mini",
|
|
167
|
+
credential: new ApiKeyCredential(config["AzureOpenAI:ApiKey"]!),
|
|
168
|
+
endpoint: new Uri(config["AzureOpenAI:Endpoint"]!)
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// Registrar agents como services
|
|
163
173
|
services.AddScoped<IReportAnalyzerAgent, ReportAnalyzerAgent>();
|
|
164
174
|
|
|
165
175
|
return services;
|
|
@@ -173,8 +183,133 @@ public class ReportGeneratorJob(IReportAnalyzerAgent analyzer)
|
|
|
173
183
|
var analysis = await analyzer.AnalyzeAsync(data, ct);
|
|
174
184
|
}
|
|
175
185
|
}
|
|
186
|
+
|
|
187
|
+
// Implementação do agent
|
|
188
|
+
public class ReportAnalyzerAgent : IReportAnalyzerAgent
|
|
189
|
+
{
|
|
190
|
+
private readonly IChatClient _chatClient;
|
|
191
|
+
|
|
192
|
+
public ReportAnalyzerAgent(IChatClient chatClient)
|
|
193
|
+
{
|
|
194
|
+
_chatClient = chatClient;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
public async Task<string> AnalyzeAsync(object data, CancellationToken ct)
|
|
198
|
+
{
|
|
199
|
+
var agent = _chatClient.CreateAgent(
|
|
200
|
+
instructions: "Você é um especialista em análise de relatórios...",
|
|
201
|
+
name: "ReportAnalyzer"
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
var response = await agent.RunAsync($"Analise: {data}", cancellationToken: ct);
|
|
205
|
+
return response.Content;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
176
208
|
```
|
|
177
209
|
|
|
210
|
+
**Referência completa:** [Agent Framework Setup](./agent-framework-setup.md)
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## 🎨 UI Component Libraries
|
|
215
|
+
|
|
216
|
+
### Decisão Arquitetural (ADR)
|
|
217
|
+
|
|
218
|
+
**Contexto:**
|
|
219
|
+
Projetos Blazor no MORPH-SPEC precisam de componentes UI consistentes, especialmente para features AI-first.
|
|
220
|
+
|
|
221
|
+
**Decisão:**
|
|
222
|
+
- **Padrão recomendado:** Fluent UI Blazor para projetos AI-first
|
|
223
|
+
- **Alternativa:** MudBlazor para SaaS tradicional
|
|
224
|
+
- **Híbrido:** Permitido quando justificado
|
|
225
|
+
|
|
226
|
+
**Razões:**
|
|
227
|
+
|
|
228
|
+
| Critério | Fluent UI | MudBlazor |
|
|
229
|
+
|----------|-----------|-----------|
|
|
230
|
+
| **AI Components** | ✅ Nativos (chat, streaming) | ❌ Não tem |
|
|
231
|
+
| **Microsoft Integration** | ✅ Agent Framework, Aspire | ❌ Terceiro |
|
|
232
|
+
| **Performance** | ✅ ~200KB | ⚠️ ~500KB |
|
|
233
|
+
| **Componentes** | ⚠️ ~50 | ✅ ~140 |
|
|
234
|
+
| **Future-proof** | ✅ Microsoft mantém | ❓ Comunidade |
|
|
235
|
+
|
|
236
|
+
**Consequências:**
|
|
237
|
+
- ✅ Melhor integração com stack Microsoft (.NET 10, Agent Framework)
|
|
238
|
+
- ✅ Performance otimizada (menor bundle)
|
|
239
|
+
- ✅ UX consistente com produtos Microsoft (Copilot, Teams)
|
|
240
|
+
- ⚠️ Pode precisar MudBlazor para grids/charts complexos
|
|
241
|
+
- ⚠️ Menos templates prontos que MudBlazor
|
|
242
|
+
|
|
243
|
+
### Matriz de Decisão
|
|
244
|
+
|
|
245
|
+
| Tipo de Projeto | UI Library Recomendada |
|
|
246
|
+
|-----------------|------------------------|
|
|
247
|
+
| SaaS com AI/chat | **Fluent UI** |
|
|
248
|
+
| SaaS com analytics pesados | **Fluent UI + MudBlazor** |
|
|
249
|
+
| Dashboard tradicional | **MudBlazor** |
|
|
250
|
+
| Admin panel simples | **Fluent UI** |
|
|
251
|
+
| Produto enterprise complexo | **Fluent UI + MudBlazor** |
|
|
252
|
+
|
|
253
|
+
### Pattern de Uso Híbrido
|
|
254
|
+
|
|
255
|
+
```csharp
|
|
256
|
+
// Program.cs - Registrar ambas libs
|
|
257
|
+
builder.Services.AddFluentUIComponents();
|
|
258
|
+
builder.Services.AddMudServices(); // Só se necessário
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
```razor
|
|
262
|
+
<!-- Usar Fluent UI para estrutura principal -->
|
|
263
|
+
<FluentLayout>
|
|
264
|
+
<FluentHeader>
|
|
265
|
+
<FluentToolbar>...</FluentToolbar>
|
|
266
|
+
</FluentHeader>
|
|
267
|
+
|
|
268
|
+
<FluentNavMenu>
|
|
269
|
+
<FluentNavLink>...</FluentNavLink>
|
|
270
|
+
</FluentNavMenu>
|
|
271
|
+
|
|
272
|
+
<FluentMain>
|
|
273
|
+
<!-- Usar MudBlazor para componentes específicos -->
|
|
274
|
+
<MudDataGrid T="Order" ...>
|
|
275
|
+
<!-- Grid complexo -->
|
|
276
|
+
</MudDataGrid>
|
|
277
|
+
|
|
278
|
+
<MudChart>
|
|
279
|
+
<!-- Charts analytics -->
|
|
280
|
+
</MudChart>
|
|
281
|
+
|
|
282
|
+
<!-- Voltar para Fluent UI para AI -->
|
|
283
|
+
<FluentMessageBar>
|
|
284
|
+
AI response
|
|
285
|
+
</FluentMessageBar>
|
|
286
|
+
</FluentMain>
|
|
287
|
+
</FluentLayout>
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Checklist de Escolha
|
|
291
|
+
|
|
292
|
+
**Use Fluent UI quando:**
|
|
293
|
+
- [ ] Projeto tem features de AI/chat
|
|
294
|
+
- [ ] Integração com Agent Framework
|
|
295
|
+
- [ ] Performance é prioridade
|
|
296
|
+
- [ ] UX tipo Copilot/Microsoft 365
|
|
297
|
+
- [ ] Budget de bundle size limitado
|
|
298
|
+
|
|
299
|
+
**Adicione MudBlazor quando:**
|
|
300
|
+
- [ ] Precisa de DataGrid avançado (filtros, agrupamento, export)
|
|
301
|
+
- [ ] Dashboards com charts customizados
|
|
302
|
+
- [ ] Componentes que Fluent UI não oferece
|
|
303
|
+
- [ ] Time já conhece MudBlazor
|
|
304
|
+
|
|
305
|
+
**Use MudBlazor 100% quando:**
|
|
306
|
+
- [ ] Projeto não tem AI
|
|
307
|
+
- [ ] Já existe codebase MudBlazor
|
|
308
|
+
- [ ] Precisa de 100+ componentes diferentes
|
|
309
|
+
- [ ] Material Design é requisito
|
|
310
|
+
|
|
311
|
+
**Referência completa:** [Fluent UI Setup](./fluent-ui-setup.md)
|
|
312
|
+
|
|
178
313
|
---
|
|
179
314
|
|
|
180
315
|
## ✅ Checklist de Arquitetura
|