@polymorphism-tech/morph-spec 8.28.0 → 8.31.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 +6 -1
- package/README.md +13 -2
- package/bin/morph-spec.js +48 -0
- package/bin/validate.js +379 -379
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +2 -0
- package/framework/MORPH.md +2 -1
- package/framework/agents.json +20 -9
- package/framework/commands/create-umbraco-lp.md +1 -1
- package/framework/commands/morph-status.md +1 -1
- package/framework/docs/CLI.md +18 -0
- package/framework/evals/rubrics/code-quality.md +17 -0
- package/framework/evals/rubrics/condensed.md +3 -1
- package/framework/hooks/claude-code/statusline.sh +11 -11
- package/framework/hooks/git/commit-msg/conventional-commits.sh +33 -33
- package/framework/hooks/git/pre-commit/agents.sh +25 -25
- package/framework/hooks/git/pre-commit/orchestrator.sh +64 -64
- package/framework/hooks/git/pre-commit/specs.sh +50 -50
- package/framework/hooks/git/pre-push/run-tests.sh +44 -44
- package/framework/hooks/shared/phase-utils.js +2 -0
- package/framework/hooks/shared/stdin-reader.js +26 -26
- package/framework/mcp/registry.json +97 -11
- package/framework/rubrics/backend.json +2 -2
- package/framework/rubrics/default.json +2 -2
- package/framework/rubrics/frontend.json +2 -2
- package/framework/schemas/tasks.schema.json +25 -0
- package/framework/skills/core/create-umbraco-lp/SKILL.md +13 -2
- package/framework/skills/core/create-umbraco-lp/references/umbraco-lp-patterns.md +598 -0
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +92 -7
- package/framework/skills/core/morph-apply/SKILL.md +12 -3
- package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
- package/framework/skills/core/morph-eval/SKILL.md +1 -1
- package/framework/skills/core/morph-hotfix/SKILL.md +1 -1
- package/framework/skills/core/morph-implement/SKILL.md +12 -2
- package/framework/skills/core/morph-plan/SKILL.md +45 -3
- package/framework/skills/core/morph-proposal/SKILL.md +1 -1
- package/framework/skills/core/morph-review/SKILL.md +11 -3
- package/framework/skills/core/morph-stack-scan/SKILL.md +13 -1
- package/framework/skills/core/morph-standards/SKILL.md +1 -1
- package/framework/skills/core/morph-uiux/SKILL.md +1 -1
- package/framework/standards/PROVENANCE.json +41 -0
- package/framework/standards/STANDARDS.json +218 -7
- package/framework/standards/ai-agents/agent-session.md +160 -160
- package/framework/standards/ai-agents/batching.md +193 -193
- package/framework/standards/ai-agents/context-providers.md +188 -188
- package/framework/standards/ai-agents/mcp-server.md +250 -250
- package/framework/standards/ai-agents/mcp-tools.md +197 -197
- package/framework/standards/ai-agents/middleware-patterns.md +207 -207
- package/framework/standards/ai-agents/modalities-image-gen.md +173 -173
- package/framework/standards/ai-agents/modalities-speech-to-text.md +171 -171
- package/framework/standards/ai-agents/modalities-text-to-speech.md +181 -181
- package/framework/standards/ai-agents/modalities-vision.md +201 -201
- package/framework/standards/ai-agents/multi-agent-patterns.md +155 -155
- package/framework/standards/ai-agents/production.md +231 -231
- package/framework/standards/ai-agents/prompts-in-db.md +214 -214
- package/framework/standards/ai-agents/providers/model-registry.md +158 -158
- package/framework/standards/ai-agents/service-tier-flex.md +135 -135
- package/framework/standards/ai-agents/structured-output.md +249 -249
- package/framework/standards/ai-agents/sweet-spot.md +109 -109
- package/framework/standards/frontend/design-system/ai-image-generation.md +43 -0
- package/framework/standards/frontend/design-system/ai-video-generation.md +113 -0
- package/framework/standards/frontend/design-system/premium-finish.md +160 -0
- package/framework/standards/frontend/gsap/gsap-core.md +1 -1
- package/framework/standards/frontend/gsap/gsap-plugins.md +1 -1
- package/framework/standards/frontend/gsap/gsap-scrolltrigger.md +3 -1
- package/framework/standards/frontend/nextjs/motion-patterns.md +3 -1
- package/framework/standards/frontend/scroll-driven/frame-scrub.md +287 -0
- package/framework/standards/frontend/scroll-driven/scroll-components.md +256 -0
- package/framework/standards/frontend/scroll-driven/smooth-scroll.md +148 -0
- package/framework/standards/frontend/seo/meta-schema-audit.md +134 -0
- package/framework/templates/.idea/morph-templates.xml +92 -0
- package/framework/templates/.vscode/morph-templates.code-snippets +186 -0
- package/framework/templates/IDE-SNIPPETS.md +262 -262
- package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
- package/framework/templates/code/dotnet/ai-agents/AgentBootstrap.cs.template +39 -39
- package/framework/templates/code/dotnet/ai-agents/EmbeddingService.cs.template +68 -68
- package/framework/templates/code/dotnet/ai-agents/ModelRegistry.cs.template +117 -117
- package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +95 -95
- package/framework/templates/code/dotnet/ai-agents/ResilientToolMiddleware.cs.template +61 -61
- package/framework/templates/code/dotnet/ai-agents/VectorSearchTool.cs.template +107 -107
- package/framework/templates/code/dotnet/ai-agents/model-registry.json.template +58 -58
- package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +281 -281
- package/framework/templates/code/dotnet/database/migration.cs +83 -83
- package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +21 -21
- package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -4
- package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -4
- package/framework/templates/code/dotnet/feature/validator.cs.hbs +15 -15
- package/framework/templates/code/sql/ai-agents/agent-prompts-migration.sql.template +58 -58
- package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -91
- package/framework/templates/code/typescript/contracts.ts +167 -167
- package/framework/templates/context/ARCHITECTURE.md +20 -0
- package/framework/templates/docs/clarifications.md +253 -253
- package/framework/templates/docs/schema-analysis.md +119 -119
- package/framework/templates/docs/ui-components.md +52 -52
- package/framework/templates/docs/ui-design-system.md +76 -76
- package/framework/templates/docs/ui-flows.md +167 -167
- package/framework/templates/docs/ui-mockups.md +98 -98
- package/framework/templates/feature/decisions.md +122 -122
- package/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +43 -43
- package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
- package/framework/templates/frontend/nextjs/env.mjs.hbs +32 -32
- package/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -56
- package/framework/templates/frontend/nextjs/page.tsx.hbs +22 -22
- package/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -26
- package/framework/templates/frontend/nextjs/use-feature.ts.hbs +54 -54
- package/framework/templates/infrastructure/docker/Dockerfile.template +58 -58
- package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
- package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
- package/framework/templates/infrastructure/github/README.md +56 -56
- package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -45
- package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -27
- package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -59
- package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -39
- package/framework/templates/integrations/asaas-client.cs +387 -387
- package/framework/templates/integrations/asaas-webhook.cs +351 -351
- package/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -76
- package/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -100
- package/framework/templates/meta-prompts/validators/pre-commit-validator.md +95 -95
- package/framework/templates/project/validate.js +120 -120
- package/framework/templates/state.template.json +17 -17
- package/framework/templates/ui/design-system.css +226 -226
- package/package.json +1 -1
- package/src/commands/dashboard/dashboard.js +53 -53
- package/src/commands/graph/affected.js +89 -0
- package/src/commands/graph/build.js +94 -0
- package/src/commands/graph/explain.js +96 -0
- package/src/commands/graph/status.js +93 -0
- package/src/commands/index.js +13 -13
- package/src/commands/project/checkpoint.js +209 -209
- package/src/commands/project/doctor.js +11 -0
- package/src/core/paths/output-schema.js +7 -0
- package/src/core/state/phase-state-machine.js +197 -197
- package/src/core/templates/template-renderer.js +477 -477
- package/src/dashboard/app/components/DetailPanel.jsx +11 -11
- package/src/dashboard/app/components/FlowGraph.jsx +17 -17
- package/src/dashboard/app/components/SearchFilter.jsx +22 -22
- package/src/dashboard/app/hooks/useDetailPanel.js +15 -15
- package/src/dashboard/app/main.jsx +13 -13
- package/src/dashboard/app/pages/AgentMap.jsx +370 -370
- package/src/dashboard/app/pages/HookInspector.jsx +418 -418
- package/src/dashboard/app/pages/PhasePipeline.jsx +408 -408
- package/src/dashboard/app/pages/RulesMap.jsx +273 -273
- package/src/dashboard/app/pages/SkillsLibrary.jsx +366 -366
- package/src/dashboard/app/pages/Standards.jsx +332 -332
- package/src/dashboard/app/styles/index.css +47 -47
- package/src/dashboard/index.html +12 -12
- package/src/dashboard/package.json +24 -24
- package/src/dashboard/scanner/phases-scanner.js +15 -15
- package/src/dashboard/scanner/rubrics-scanner.js +12 -12
- package/src/dashboard/scanner/rules-scanner.js +37 -37
- package/src/dashboard/scanner/skills-scanner.js +43 -43
- package/src/dashboard/scanner/squads-scanner.js +13 -13
- package/src/dashboard/vite-plugin-morph-data.js +17 -17
- package/src/dashboard/vite.config.js +24 -24
- package/src/lib/detectors/design-system-detector.js +188 -188
- package/src/lib/detectors/index.js +217 -217
- package/src/lib/generators/architecture-scanner.js +45 -4
- package/src/lib/generators/design-system-generator.js +508 -508
- package/src/lib/generators/settings-generator.js +209 -209
- package/src/lib/graph/god-nodes.js +75 -0
- package/src/lib/graph/graph-health.js +61 -0
- package/src/lib/graph/graph-loader.js +86 -0
- package/src/lib/graph/graphify-runtime.js +100 -0
- package/src/lib/graph/graphifyignore.js +86 -0
- package/src/lib/graph/sanitize.js +280 -0
- package/src/lib/hooks/hook-executor.js +167 -167
- package/src/lib/installers/mcp-installer.js +719 -719
- package/src/lib/tasks/task-classifier.js +30 -30
- package/src/lib/tasks/task-parser.js +209 -209
- package/src/lib/tasks/tasks-json-parser.js +26 -0
- package/src/lib/validators/checkpoint-persistence.js +39 -39
- package/src/lib/validators/css/css-validator.js +340 -340
- package/src/lib/validators/reuse/index.js +10 -0
- package/src/lib/validators/reuse/reuse-validator.js +324 -0
- package/src/lib/validators/reuse/symbol-scanner.js +144 -0
- package/src/lib/validators/shared/emit-validator-dispatch.js +14 -14
- package/src/lib/validators/shared/issue-counter.js +14 -14
- package/src/lib/validators/validation-runner.js +40 -1
- package/src/scripts/setup-infra.js +60 -1
- package/src/utils/agent-id-mapper.js +11 -11
- package/src/utils/claude-settings-manager.js +300 -300
- package/src/utils/file-copier.js +40 -0
- package/src/utils/skills-installer.js +187 -187
|
@@ -1,158 +1,158 @@
|
|
|
1
|
-
# Model Registry — Provider-agnostic agent configuration
|
|
2
|
-
|
|
3
|
-
> **Scope:** stacks=["dotnet"]
|
|
4
|
-
> **Layer:** 0 (always-load via persona maf-expert)
|
|
5
|
-
> **Keywords:** model registry, provider agnostic, model alias, IChatClient factory, multi-model, model selection, model config
|
|
6
|
-
> **Read by Claude in:** plan (cita este standard quando feature menciona >1 modelo ou multi-provider) + implement (copia o template ModelRegistry.cs e gera config no projeto)
|
|
7
|
-
|
|
8
|
-
**Verified against:** MAF 1.0 GA + tier list research (2026-05-18). Last-verified: 2026-05-19.
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## Pattern
|
|
13
|
-
|
|
14
|
-
The project consuming morph-spec maintains a **single JSON file** mapping aliases (`text-default`, `vision`, `reasoning`, etc.) to `{ provider, model, options }`. Agents reference aliases — never hardcoded model strings. Switching provider or model is a one-file change.
|
|
15
|
-
|
|
16
|
-
```
|
|
17
|
-
Standard (this file, in framework) — explains the pattern + canonical schema
|
|
18
|
-
│ Claude reads + copies template
|
|
19
|
-
▼
|
|
20
|
-
Project (consumer) — config/model-registry.json + src/.../ModelRegistry.cs
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## Schema (canonical)
|
|
26
|
-
|
|
27
|
-
```jsonc
|
|
28
|
-
// config/model-registry.json — IN THE PROJECT (not in framework)
|
|
29
|
-
{
|
|
30
|
-
"$schema": "./model-registry.schema.json",
|
|
31
|
-
"version": "1.0",
|
|
32
|
-
"defaultAlias": "text-default",
|
|
33
|
-
"aliases": {
|
|
34
|
-
"text-default": { "provider": "openai", "model": "gpt-4o-mini", "options": { "temperature": 0.7 } },
|
|
35
|
-
"text-heavy": { "provider": "openai", "model": "gpt-4o", "options": { "temperature": 0.5 } },
|
|
36
|
-
"reasoning": { "provider": "openai", "model": "o3-mini", "options": { "reasoningEffort": "medium" } },
|
|
37
|
-
"long-form": { "provider": "anthropic", "model": "claude-sonnet-4-6", "options": {} },
|
|
38
|
-
"vision": { "provider": "google", "model": "gemini-2.5-flash", "options": {} },
|
|
39
|
-
"embeddings": { "provider": "openai", "model": "text-embedding-3-small", "options": { "dimensions": 1536 } },
|
|
40
|
-
"transcription": { "provider": "openai", "model": "whisper-1", "options": {} },
|
|
41
|
-
"local-dev": { "provider": "ollama", "model": "llama3.2:3b", "options": { "endpoint": "http://localhost:11434/v1" } }
|
|
42
|
-
},
|
|
43
|
-
"fallback": {
|
|
44
|
-
"text-default": "anthropic/claude-haiku-4-5",
|
|
45
|
-
"text-heavy": "anthropic/claude-sonnet-4-6"
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
> The aliases above are an **example**. Each project defines its own — provider choices vary per feature.
|
|
51
|
-
|
|
52
|
-
**Field semantics:**
|
|
53
|
-
- `provider`: SDK family — one of `openai`, `google`, `anthropic`, `ollama` (first-class). `azure-openai` is supported as an opt-in branch (see §providers).
|
|
54
|
-
- `model`: model id for that provider.
|
|
55
|
-
- `options`: provider-specific extras (temperature, reasoning effort, `endpoint` for Ollama, etc.).
|
|
56
|
-
- `fallback`: when the primary provider fails (rate limit, outage), switch to this alias. Format `provider/model`.
|
|
57
|
-
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
## Providers (first-class)
|
|
61
|
-
|
|
62
|
-
> **This section is the single source of truth for provider SDKs.** Provider SDKs change names/versions often — keep this section verified with a date; templates stay stable.
|
|
63
|
-
|
|
64
|
-
| Provider | `provider` value | NuGet SDK (LAST-VERIFIED 2026-05-19) | Notes |
|
|
65
|
-
|----------|------------------|--------------------------------------|-------|
|
|
66
|
-
| **OpenAI** | `openai` | `OpenAI` 2.* | `new ChatClient(model, apiKey).AsIChatClient()` |
|
|
67
|
-
| **Ollama** | `ollama` | `OpenAI` 2.* (OpenAI-compatible endpoint) | Same `ChatClient` with custom `Endpoint` + dummy key |
|
|
68
|
-
| **Google Gemini** | `google` | Confirm current SDK on NuGet before use | Adapt provider client to `IChatClient` |
|
|
69
|
-
| **Anthropic Claude** | `anthropic` | Confirm current SDK on NuGet before use | Adapt provider client to `IChatClient` |
|
|
70
|
-
| **Azure OpenAI** (opt-in, not default) | `azure-openai` | `Azure.AI.OpenAI` 2.* + `Azure.Identity` | Add only when a client requires data residency |
|
|
71
|
-
|
|
72
|
-
**Adding a provider branch:** the `ModelRegistry.cs` template implements `openai` + `ollama`. To add `google`, `anthropic`, or `azure-openai`:
|
|
73
|
-
1. Confirm the current NuGet SDK — community SDKs evolve; check NuGet/context7 before coding.
|
|
74
|
-
2. Add a `case "<provider>":` branch in `ModelRegistry.GetChatClient`'s switch, following the `openai`/`ollama` pattern.
|
|
75
|
-
3. Add the SDK `PackageReference` to the project's `.csproj`.
|
|
76
|
-
4. The branch returns an `IChatClient`. If the SDK doesn't expose `IChatClient` natively, wrap it with an adapter.
|
|
77
|
-
|
|
78
|
-
**Direct models only:** never use a hosted agent service. Every provider above is reached as a direct model.
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
## Implementation pattern
|
|
83
|
-
|
|
84
|
-
```csharp
|
|
85
|
-
// WRONG — hardcoded model + provider
|
|
86
|
-
var agent = new ChatClient("gpt-4o-mini", apiKey)
|
|
87
|
-
.AsIChatClient()
|
|
88
|
-
.AsAIAgent(instructions: prompt);
|
|
89
|
-
|
|
90
|
-
// RIGHT — alias-based, provider-agnostic
|
|
91
|
-
var agent = _modelRegistry.GetChatClient("text-default")
|
|
92
|
-
.AsAIAgent(instructions: prompt);
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
The `ModelRegistry` class in the project owns the mapping. See template `templates/code/dotnet/ai-agents/ModelRegistry.cs.template`.
|
|
96
|
-
|
|
97
|
-
---
|
|
98
|
-
|
|
99
|
-
## How Claude implements this in a project
|
|
100
|
-
|
|
101
|
-
When a task says "register the X agent" and the project has >1 model or >1 provider, Claude:
|
|
102
|
-
|
|
103
|
-
1. Read this standard.
|
|
104
|
-
2. Copy `templates/code/dotnet/ai-agents/ModelRegistry.cs.template` to `src/.../ModelRegistry.cs` in the project. Substitute placeholders.
|
|
105
|
-
3. Copy `templates/code/dotnet/ai-agents/model-registry.json.template` to `config/model-registry.json`. Adjust aliases to project needs.
|
|
106
|
-
4. Wire `ModelRegistry` into DI (see `AgentBootstrap.cs.template`).
|
|
107
|
-
5. Future agents reference `_modelRegistry.GetChatClient(alias)`.
|
|
108
|
-
|
|
109
|
-
---
|
|
110
|
-
|
|
111
|
-
## Recommended aliases & models (orientativo — maio/2026)
|
|
112
|
-
|
|
113
|
-
> Tabela orientativa. Actual values live in the project's `model-registry.json`. Models evolve fast.
|
|
114
|
-
|
|
115
|
-
| Alias | Provider sugerido | Modelo (maio/2026) | Use case |
|
|
116
|
-
|-------|-------------------|--------------------|----------|
|
|
117
|
-
| `text-default` | openai | gpt-4o-mini | Geração padrão de texto |
|
|
118
|
-
| `text-heavy` | openai / anthropic | gpt-4o / claude-sonnet-4-6 | Análise complexa |
|
|
119
|
-
| `reasoning` | openai | o3-mini | Decisões, planejamento, math |
|
|
120
|
-
| `long-form` | anthropic | claude-sonnet-4-6 | Escrita longa, análise de documento |
|
|
121
|
-
| `vision` | google / openai | gemini-2.5-flash / gpt-4o | Image → Text |
|
|
122
|
-
| `embeddings` | openai | text-embedding-3-small | RAG, similarity |
|
|
123
|
-
| `transcription` | openai | whisper-1 | Audio → Text |
|
|
124
|
-
| `local-dev` | ollama | llama3.2:3b | Dev local, sem custo |
|
|
125
|
-
|
|
126
|
-
---
|
|
127
|
-
|
|
128
|
-
## Anti-patterns
|
|
129
|
-
|
|
130
|
-
| Anti-pattern | Why | Right way |
|
|
131
|
-
|--------------|-----|-----------|
|
|
132
|
-
| Hardcode `"gpt-4o-mini"` in agent code | Switching model = grep + replace | Use `_modelRegistry.GetChatClient("text-default")` |
|
|
133
|
-
| Put `model-registry.json` in `.morph/` | `.morph/framework` is framework-only; `.morph/config/config.json` is reserved for morph-spec metadata | Put it in `config/` of the project |
|
|
134
|
-
| Different `ModelRegistry` class per agent | Defeats the purpose | One class per project, singleton in DI |
|
|
135
|
-
| Use a hosted agent service to "simplify" | Hosted lags 6-9 months, removes control | Always direct models |
|
|
136
|
-
| Mix providers without a `fallback` block | Hard to diagnose outages | Declare `fallback` in `model-registry.json` |
|
|
137
|
-
|
|
138
|
-
---
|
|
139
|
-
|
|
140
|
-
## Checklist (verifiable by morph-eval)
|
|
141
|
-
|
|
142
|
-
- [ ] Project has `config/model-registry.json` (or declared equivalent).
|
|
143
|
-
- [ ] Project has a `ModelRegistry` class registered as singleton in DI.
|
|
144
|
-
- [ ] No agent code has hardcoded model strings — `grep -rE 'gpt-[0-9]|claude-|gemini-|whisper-' src/` matches only `ModelRegistry.cs`.
|
|
145
|
-
- [ ] Aliases used in agent code exist in `model-registry.json`.
|
|
146
|
-
|
|
147
|
-
---
|
|
148
|
-
|
|
149
|
-
## References
|
|
150
|
-
|
|
151
|
-
- `ai-agents-setup` — provider SDKs
|
|
152
|
-
- Template: `templates/code/dotnet/ai-agents/ModelRegistry.cs.template`
|
|
153
|
-
- Template: `templates/code/dotnet/ai-agents/model-registry.json.template`
|
|
154
|
-
- Template: `templates/code/dotnet/ai-agents/AgentBootstrap.cs.template`
|
|
155
|
-
|
|
156
|
-
---
|
|
157
|
-
|
|
158
|
-
*MORPH-SPEC by Polymorphism Tech — ai-agents/providers/model-registry.md v1.0 (2026-05-19)*
|
|
1
|
+
# Model Registry — Provider-agnostic agent configuration
|
|
2
|
+
|
|
3
|
+
> **Scope:** stacks=["dotnet"]
|
|
4
|
+
> **Layer:** 0 (always-load via persona maf-expert)
|
|
5
|
+
> **Keywords:** model registry, provider agnostic, model alias, IChatClient factory, multi-model, model selection, model config
|
|
6
|
+
> **Read by Claude in:** plan (cita este standard quando feature menciona >1 modelo ou multi-provider) + implement (copia o template ModelRegistry.cs e gera config no projeto)
|
|
7
|
+
|
|
8
|
+
**Verified against:** MAF 1.0 GA + tier list research (2026-05-18). Last-verified: 2026-05-19.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Pattern
|
|
13
|
+
|
|
14
|
+
The project consuming morph-spec maintains a **single JSON file** mapping aliases (`text-default`, `vision`, `reasoning`, etc.) to `{ provider, model, options }`. Agents reference aliases — never hardcoded model strings. Switching provider or model is a one-file change.
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
Standard (this file, in framework) — explains the pattern + canonical schema
|
|
18
|
+
│ Claude reads + copies template
|
|
19
|
+
▼
|
|
20
|
+
Project (consumer) — config/model-registry.json + src/.../ModelRegistry.cs
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Schema (canonical)
|
|
26
|
+
|
|
27
|
+
```jsonc
|
|
28
|
+
// config/model-registry.json — IN THE PROJECT (not in framework)
|
|
29
|
+
{
|
|
30
|
+
"$schema": "./model-registry.schema.json",
|
|
31
|
+
"version": "1.0",
|
|
32
|
+
"defaultAlias": "text-default",
|
|
33
|
+
"aliases": {
|
|
34
|
+
"text-default": { "provider": "openai", "model": "gpt-4o-mini", "options": { "temperature": 0.7 } },
|
|
35
|
+
"text-heavy": { "provider": "openai", "model": "gpt-4o", "options": { "temperature": 0.5 } },
|
|
36
|
+
"reasoning": { "provider": "openai", "model": "o3-mini", "options": { "reasoningEffort": "medium" } },
|
|
37
|
+
"long-form": { "provider": "anthropic", "model": "claude-sonnet-4-6", "options": {} },
|
|
38
|
+
"vision": { "provider": "google", "model": "gemini-2.5-flash", "options": {} },
|
|
39
|
+
"embeddings": { "provider": "openai", "model": "text-embedding-3-small", "options": { "dimensions": 1536 } },
|
|
40
|
+
"transcription": { "provider": "openai", "model": "whisper-1", "options": {} },
|
|
41
|
+
"local-dev": { "provider": "ollama", "model": "llama3.2:3b", "options": { "endpoint": "http://localhost:11434/v1" } }
|
|
42
|
+
},
|
|
43
|
+
"fallback": {
|
|
44
|
+
"text-default": "anthropic/claude-haiku-4-5",
|
|
45
|
+
"text-heavy": "anthropic/claude-sonnet-4-6"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
> The aliases above are an **example**. Each project defines its own — provider choices vary per feature.
|
|
51
|
+
|
|
52
|
+
**Field semantics:**
|
|
53
|
+
- `provider`: SDK family — one of `openai`, `google`, `anthropic`, `ollama` (first-class). `azure-openai` is supported as an opt-in branch (see §providers).
|
|
54
|
+
- `model`: model id for that provider.
|
|
55
|
+
- `options`: provider-specific extras (temperature, reasoning effort, `endpoint` for Ollama, etc.).
|
|
56
|
+
- `fallback`: when the primary provider fails (rate limit, outage), switch to this alias. Format `provider/model`.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Providers (first-class)
|
|
61
|
+
|
|
62
|
+
> **This section is the single source of truth for provider SDKs.** Provider SDKs change names/versions often — keep this section verified with a date; templates stay stable.
|
|
63
|
+
|
|
64
|
+
| Provider | `provider` value | NuGet SDK (LAST-VERIFIED 2026-05-19) | Notes |
|
|
65
|
+
|----------|------------------|--------------------------------------|-------|
|
|
66
|
+
| **OpenAI** | `openai` | `OpenAI` 2.* | `new ChatClient(model, apiKey).AsIChatClient()` |
|
|
67
|
+
| **Ollama** | `ollama` | `OpenAI` 2.* (OpenAI-compatible endpoint) | Same `ChatClient` with custom `Endpoint` + dummy key |
|
|
68
|
+
| **Google Gemini** | `google` | Confirm current SDK on NuGet before use | Adapt provider client to `IChatClient` |
|
|
69
|
+
| **Anthropic Claude** | `anthropic` | Confirm current SDK on NuGet before use | Adapt provider client to `IChatClient` |
|
|
70
|
+
| **Azure OpenAI** (opt-in, not default) | `azure-openai` | `Azure.AI.OpenAI` 2.* + `Azure.Identity` | Add only when a client requires data residency |
|
|
71
|
+
|
|
72
|
+
**Adding a provider branch:** the `ModelRegistry.cs` template implements `openai` + `ollama`. To add `google`, `anthropic`, or `azure-openai`:
|
|
73
|
+
1. Confirm the current NuGet SDK — community SDKs evolve; check NuGet/context7 before coding.
|
|
74
|
+
2. Add a `case "<provider>":` branch in `ModelRegistry.GetChatClient`'s switch, following the `openai`/`ollama` pattern.
|
|
75
|
+
3. Add the SDK `PackageReference` to the project's `.csproj`.
|
|
76
|
+
4. The branch returns an `IChatClient`. If the SDK doesn't expose `IChatClient` natively, wrap it with an adapter.
|
|
77
|
+
|
|
78
|
+
**Direct models only:** never use a hosted agent service. Every provider above is reached as a direct model.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Implementation pattern
|
|
83
|
+
|
|
84
|
+
```csharp
|
|
85
|
+
// WRONG — hardcoded model + provider
|
|
86
|
+
var agent = new ChatClient("gpt-4o-mini", apiKey)
|
|
87
|
+
.AsIChatClient()
|
|
88
|
+
.AsAIAgent(instructions: prompt);
|
|
89
|
+
|
|
90
|
+
// RIGHT — alias-based, provider-agnostic
|
|
91
|
+
var agent = _modelRegistry.GetChatClient("text-default")
|
|
92
|
+
.AsAIAgent(instructions: prompt);
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The `ModelRegistry` class in the project owns the mapping. See template `templates/code/dotnet/ai-agents/ModelRegistry.cs.template`.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## How Claude implements this in a project
|
|
100
|
+
|
|
101
|
+
When a task says "register the X agent" and the project has >1 model or >1 provider, Claude:
|
|
102
|
+
|
|
103
|
+
1. Read this standard.
|
|
104
|
+
2. Copy `templates/code/dotnet/ai-agents/ModelRegistry.cs.template` to `src/.../ModelRegistry.cs` in the project. Substitute placeholders.
|
|
105
|
+
3. Copy `templates/code/dotnet/ai-agents/model-registry.json.template` to `config/model-registry.json`. Adjust aliases to project needs.
|
|
106
|
+
4. Wire `ModelRegistry` into DI (see `AgentBootstrap.cs.template`).
|
|
107
|
+
5. Future agents reference `_modelRegistry.GetChatClient(alias)`.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Recommended aliases & models (orientativo — maio/2026)
|
|
112
|
+
|
|
113
|
+
> Tabela orientativa. Actual values live in the project's `model-registry.json`. Models evolve fast.
|
|
114
|
+
|
|
115
|
+
| Alias | Provider sugerido | Modelo (maio/2026) | Use case |
|
|
116
|
+
|-------|-------------------|--------------------|----------|
|
|
117
|
+
| `text-default` | openai | gpt-4o-mini | Geração padrão de texto |
|
|
118
|
+
| `text-heavy` | openai / anthropic | gpt-4o / claude-sonnet-4-6 | Análise complexa |
|
|
119
|
+
| `reasoning` | openai | o3-mini | Decisões, planejamento, math |
|
|
120
|
+
| `long-form` | anthropic | claude-sonnet-4-6 | Escrita longa, análise de documento |
|
|
121
|
+
| `vision` | google / openai | gemini-2.5-flash / gpt-4o | Image → Text |
|
|
122
|
+
| `embeddings` | openai | text-embedding-3-small | RAG, similarity |
|
|
123
|
+
| `transcription` | openai | whisper-1 | Audio → Text |
|
|
124
|
+
| `local-dev` | ollama | llama3.2:3b | Dev local, sem custo |
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Anti-patterns
|
|
129
|
+
|
|
130
|
+
| Anti-pattern | Why | Right way |
|
|
131
|
+
|--------------|-----|-----------|
|
|
132
|
+
| Hardcode `"gpt-4o-mini"` in agent code | Switching model = grep + replace | Use `_modelRegistry.GetChatClient("text-default")` |
|
|
133
|
+
| Put `model-registry.json` in `.morph/` | `.morph/framework` is framework-only; `.morph/config/config.json` is reserved for morph-spec metadata | Put it in `config/` of the project |
|
|
134
|
+
| Different `ModelRegistry` class per agent | Defeats the purpose | One class per project, singleton in DI |
|
|
135
|
+
| Use a hosted agent service to "simplify" | Hosted lags 6-9 months, removes control | Always direct models |
|
|
136
|
+
| Mix providers without a `fallback` block | Hard to diagnose outages | Declare `fallback` in `model-registry.json` |
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Checklist (verifiable by morph-eval)
|
|
141
|
+
|
|
142
|
+
- [ ] Project has `config/model-registry.json` (or declared equivalent).
|
|
143
|
+
- [ ] Project has a `ModelRegistry` class registered as singleton in DI.
|
|
144
|
+
- [ ] No agent code has hardcoded model strings — `grep -rE 'gpt-[0-9]|claude-|gemini-|whisper-' src/` matches only `ModelRegistry.cs`.
|
|
145
|
+
- [ ] Aliases used in agent code exist in `model-registry.json`.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## References
|
|
150
|
+
|
|
151
|
+
- `ai-agents-setup` — provider SDKs
|
|
152
|
+
- Template: `templates/code/dotnet/ai-agents/ModelRegistry.cs.template`
|
|
153
|
+
- Template: `templates/code/dotnet/ai-agents/model-registry.json.template`
|
|
154
|
+
- Template: `templates/code/dotnet/ai-agents/AgentBootstrap.cs.template`
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
*MORPH-SPEC by Polymorphism Tech — ai-agents/providers/model-registry.md v1.0 (2026-05-19)*
|
|
@@ -1,135 +1,135 @@
|
|
|
1
|
-
# Service Tier Flex — Cost-optimized tier for async work
|
|
2
|
-
|
|
3
|
-
> **Scope:** stacks=["dotnet"]
|
|
4
|
-
> **Layer:** 2 (on-keyword)
|
|
5
|
-
> **Keywords:** service tier, flex tier, cost optimization, async tier, priority tier
|
|
6
|
-
> **Read by Claude in:** implement
|
|
7
|
-
|
|
8
|
-
**Verified against:** MAF 1.0 GA + OpenAI .NET SDK 2.* (campo `service_tier` confirmado pela REST API; nome da propriedade C# marcado `// VERIFY:` — ver seção A API). Last-verified: 2026-05-19.
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## Quando usar tier flex
|
|
13
|
-
|
|
14
|
-
Use o service tier **flex** quando o agente roda em background, sem usuário aguardando resposta:
|
|
15
|
-
|
|
16
|
-
- Relatório mensal gerado overnight (briefing, sumário financeiro, newsletter)
|
|
17
|
-
- Job de enriquecimento de dados disparado por evento (upload de arquivo, fim de período)
|
|
18
|
-
- Análise on-demand que pode demorar segundos a mais sem impacto na UX
|
|
19
|
-
- Qualquer completion dentro de um Worker Service / Hangfire job
|
|
20
|
-
|
|
21
|
-
**Por que usar:** tier flex troca velocidade de resposta por **custo menor**. A OpenAI processa requests flex com menor prioridade — SLA mais relaxado, desconto de custo.
|
|
22
|
-
|
|
23
|
-
> Regra: se o resultado vai para um banco de dados ou fila (não direto ao usuário), use flex.
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## A API
|
|
28
|
-
|
|
29
|
-
> **AVISO:** service tier é **OpenAI-specific** — não é exposto no `Microsoft.Extensions.AI.ChatOptions`.
|
|
30
|
-
> Para setar service tier, use o `ChatClient` direto (obtido do Model Registry ou da configuração).
|
|
31
|
-
|
|
32
|
-
> ### ⚠️ Status de verificação da API .NET
|
|
33
|
-
>
|
|
34
|
-
> **Confirmado pela REST API da OpenAI:** o campo é `service_tier`, com valores `"auto"`,
|
|
35
|
-
> `"default"` e `"flex"`.
|
|
36
|
-
>
|
|
37
|
-
> **A confirmar contra o pacote `OpenAI` 2.\* instalado** (marcado `// VERIFY:` no código):
|
|
38
|
-
> o nome exato da propriedade C# em `ChatCompletionOptions` e se os valores são `string`
|
|
39
|
-
> constants ou membros de um enum (ex.: `ChatServiceTier.Flex`). O context7 não retornou a
|
|
40
|
-
> superfície de `ChatCompletionOptions` para batch/tier — confirme no IntelliSense antes de codar.
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## Exemplo C#
|
|
45
|
-
|
|
46
|
-
```csharp
|
|
47
|
-
using OpenAI;
|
|
48
|
-
using OpenAI.Chat;
|
|
49
|
-
using System.ClientModel;
|
|
50
|
-
using Microsoft.Agents.AI;
|
|
51
|
-
using Microsoft.Extensions.AI;
|
|
52
|
-
|
|
53
|
-
// ── Opção A: usando ChatClient direto (para um job async simples) ──
|
|
54
|
-
var apiKey = configuration["OpenAI:ApiKey"]!;
|
|
55
|
-
var model = configuration["OpenAI:Model"] ?? "gpt-4o-mini";
|
|
56
|
-
|
|
57
|
-
ChatClient chatClient = new(model, new ApiKeyCredential(apiKey));
|
|
58
|
-
|
|
59
|
-
ChatCompletionOptions flexOptions = new()
|
|
60
|
-
{
|
|
61
|
-
// VERIFY nome da propriedade e tipo do valor — string "flex" ou enum (ChatServiceTier.Flex).
|
|
62
|
-
// Ver "Status de verificação da API .NET" acima.
|
|
63
|
-
ServiceTier = "flex",
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
ChatCompletion result = await chatClient.CompleteChatAsync(
|
|
67
|
-
messages: [new UserChatMessage(prompt)],
|
|
68
|
-
options: flexOptions);
|
|
69
|
-
|
|
70
|
-
string responseText = result.Content[0].Text;
|
|
71
|
-
|
|
72
|
-
// ── Opção B: dentro de um AIAgent MAF ──
|
|
73
|
-
// O agente MAF usa o IChatClient abstrato — ServiceTier (OpenAI-specific) não é exposto
|
|
74
|
-
// pelo Microsoft.Extensions.AI.ChatOptions, então não passa direto pelo AgentRunOptions.
|
|
75
|
-
// Para flex tier num agente, injete-o num middleware de IChatClient que monta
|
|
76
|
-
// ChatCompletionOptions com ServiceTier (ver ai-agents-middleware-patterns).
|
|
77
|
-
// Recomendação: para jobs async simples que precisam de flex tier, prefira a Opção A
|
|
78
|
-
// (ChatClient direto) — é o caminho confirmado e sem indireção.
|
|
79
|
-
|
|
80
|
-
// Exemplo Worker Service — dispara o job async e não bloqueia o caller:
|
|
81
|
-
// services.AddHostedService<MonthlyReportWorker>();
|
|
82
|
-
// MonthlyReportWorker usa chatClient com flexOptions para cada completion.
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
> Para jobs que rodam no contexto de um MAF agent mas precisam de flex tier:
|
|
86
|
-
> o agent pode ser construído sobre um `IChatClient` wrappado em middleware que injeta
|
|
87
|
-
> `ServiceTier = "flex"` via `ChatCompletionOptions` — veja `ai-agents-middleware-patterns`.
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
## Decision
|
|
92
|
-
|
|
93
|
-
| Cenário | Service tier recomendado |
|
|
94
|
-
|---------|--------------------------|
|
|
95
|
-
| Chat com usuário aguardando na tela | `default` (ou `auto`) |
|
|
96
|
-
| Job async — relatório, enriquecimento, briefing | `flex` |
|
|
97
|
-
| Job de alta prioridade com SLA apertado | `priority` (disponibilidade depende do plano OpenAI da conta) |
|
|
98
|
-
| Batch API (24 h) | Não se aplica — Batch tem custo próprio |
|
|
99
|
-
|
|
100
|
-
> `auto` (padrão da API): OpenAI decide o tier baseado na carga. Use `flex` explícito
|
|
101
|
-
> quando você quer garantir o menor custo para trabalho assíncrono.
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## Anti-patterns
|
|
106
|
-
|
|
107
|
-
| Anti-pattern | Problema |
|
|
108
|
-
|-------------|----------|
|
|
109
|
-
| Usar `flex` em completion interativa | Latência imprevisível — usuário percebe lentidão |
|
|
110
|
-
| Usar `priority` (ou `default`) em batch noturno | Paga mais sem necessidade |
|
|
111
|
-
| Espalhar `ServiceTier = "flex"` por vários handlers | Usar middleware de ChatOptions para centralizar |
|
|
112
|
-
| Combinar flex tier com Batch API | São mecanismos distintos; não se somam |
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
|
|
116
|
-
## Checklist (verifiable by morph-eval)
|
|
117
|
-
|
|
118
|
-
- [ ] Tier flex usado somente em jobs assíncronos (Worker Service / Hangfire), nunca em handlers de request HTTP síncrono
|
|
119
|
-
- [ ] `ServiceTier` confirmado como string `"flex"` ou enum correto na versão do SDK instalada no projeto
|
|
120
|
-
- [ ] Jobs com flex tier não têm SLA de latência definido no contrato com o usuário final
|
|
121
|
-
- [ ] Se o agente usa `IChatClient` abstrato, o `ServiceTier` foi validado que é passado corretamente
|
|
122
|
-
|
|
123
|
-
---
|
|
124
|
-
|
|
125
|
-
## References
|
|
126
|
-
|
|
127
|
-
- `ai-agents-setup` — packages e configuração do cliente OpenAI
|
|
128
|
-
- `ai-agents-batching` — alternativa de custo para volume alto de prompts independentes
|
|
129
|
-
- `ai-agents-middleware-patterns` (Onda 2) — middleware para injetar `ChatOptions` globalmente
|
|
130
|
-
- `ai-agents-providers-model-registry` — configuração provider-agnostic
|
|
131
|
-
- OpenAI Service Tiers: https://platform.openai.com/docs/guides/service-tiers
|
|
132
|
-
|
|
133
|
-
---
|
|
134
|
-
|
|
135
|
-
*MORPH-SPEC by Polymorphism Tech — ai-agents/service-tier-flex.md v1.0 (2026-05-19)*
|
|
1
|
+
# Service Tier Flex — Cost-optimized tier for async work
|
|
2
|
+
|
|
3
|
+
> **Scope:** stacks=["dotnet"]
|
|
4
|
+
> **Layer:** 2 (on-keyword)
|
|
5
|
+
> **Keywords:** service tier, flex tier, cost optimization, async tier, priority tier
|
|
6
|
+
> **Read by Claude in:** implement
|
|
7
|
+
|
|
8
|
+
**Verified against:** MAF 1.0 GA + OpenAI .NET SDK 2.* (campo `service_tier` confirmado pela REST API; nome da propriedade C# marcado `// VERIFY:` — ver seção A API). Last-verified: 2026-05-19.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Quando usar tier flex
|
|
13
|
+
|
|
14
|
+
Use o service tier **flex** quando o agente roda em background, sem usuário aguardando resposta:
|
|
15
|
+
|
|
16
|
+
- Relatório mensal gerado overnight (briefing, sumário financeiro, newsletter)
|
|
17
|
+
- Job de enriquecimento de dados disparado por evento (upload de arquivo, fim de período)
|
|
18
|
+
- Análise on-demand que pode demorar segundos a mais sem impacto na UX
|
|
19
|
+
- Qualquer completion dentro de um Worker Service / Hangfire job
|
|
20
|
+
|
|
21
|
+
**Por que usar:** tier flex troca velocidade de resposta por **custo menor**. A OpenAI processa requests flex com menor prioridade — SLA mais relaxado, desconto de custo.
|
|
22
|
+
|
|
23
|
+
> Regra: se o resultado vai para um banco de dados ou fila (não direto ao usuário), use flex.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## A API
|
|
28
|
+
|
|
29
|
+
> **AVISO:** service tier é **OpenAI-specific** — não é exposto no `Microsoft.Extensions.AI.ChatOptions`.
|
|
30
|
+
> Para setar service tier, use o `ChatClient` direto (obtido do Model Registry ou da configuração).
|
|
31
|
+
|
|
32
|
+
> ### ⚠️ Status de verificação da API .NET
|
|
33
|
+
>
|
|
34
|
+
> **Confirmado pela REST API da OpenAI:** o campo é `service_tier`, com valores `"auto"`,
|
|
35
|
+
> `"default"` e `"flex"`.
|
|
36
|
+
>
|
|
37
|
+
> **A confirmar contra o pacote `OpenAI` 2.\* instalado** (marcado `// VERIFY:` no código):
|
|
38
|
+
> o nome exato da propriedade C# em `ChatCompletionOptions` e se os valores são `string`
|
|
39
|
+
> constants ou membros de um enum (ex.: `ChatServiceTier.Flex`). O context7 não retornou a
|
|
40
|
+
> superfície de `ChatCompletionOptions` para batch/tier — confirme no IntelliSense antes de codar.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Exemplo C#
|
|
45
|
+
|
|
46
|
+
```csharp
|
|
47
|
+
using OpenAI;
|
|
48
|
+
using OpenAI.Chat;
|
|
49
|
+
using System.ClientModel;
|
|
50
|
+
using Microsoft.Agents.AI;
|
|
51
|
+
using Microsoft.Extensions.AI;
|
|
52
|
+
|
|
53
|
+
// ── Opção A: usando ChatClient direto (para um job async simples) ──
|
|
54
|
+
var apiKey = configuration["OpenAI:ApiKey"]!;
|
|
55
|
+
var model = configuration["OpenAI:Model"] ?? "gpt-4o-mini";
|
|
56
|
+
|
|
57
|
+
ChatClient chatClient = new(model, new ApiKeyCredential(apiKey));
|
|
58
|
+
|
|
59
|
+
ChatCompletionOptions flexOptions = new()
|
|
60
|
+
{
|
|
61
|
+
// VERIFY nome da propriedade e tipo do valor — string "flex" ou enum (ChatServiceTier.Flex).
|
|
62
|
+
// Ver "Status de verificação da API .NET" acima.
|
|
63
|
+
ServiceTier = "flex",
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
ChatCompletion result = await chatClient.CompleteChatAsync(
|
|
67
|
+
messages: [new UserChatMessage(prompt)],
|
|
68
|
+
options: flexOptions);
|
|
69
|
+
|
|
70
|
+
string responseText = result.Content[0].Text;
|
|
71
|
+
|
|
72
|
+
// ── Opção B: dentro de um AIAgent MAF ──
|
|
73
|
+
// O agente MAF usa o IChatClient abstrato — ServiceTier (OpenAI-specific) não é exposto
|
|
74
|
+
// pelo Microsoft.Extensions.AI.ChatOptions, então não passa direto pelo AgentRunOptions.
|
|
75
|
+
// Para flex tier num agente, injete-o num middleware de IChatClient que monta
|
|
76
|
+
// ChatCompletionOptions com ServiceTier (ver ai-agents-middleware-patterns).
|
|
77
|
+
// Recomendação: para jobs async simples que precisam de flex tier, prefira a Opção A
|
|
78
|
+
// (ChatClient direto) — é o caminho confirmado e sem indireção.
|
|
79
|
+
|
|
80
|
+
// Exemplo Worker Service — dispara o job async e não bloqueia o caller:
|
|
81
|
+
// services.AddHostedService<MonthlyReportWorker>();
|
|
82
|
+
// MonthlyReportWorker usa chatClient com flexOptions para cada completion.
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
> Para jobs que rodam no contexto de um MAF agent mas precisam de flex tier:
|
|
86
|
+
> o agent pode ser construído sobre um `IChatClient` wrappado em middleware que injeta
|
|
87
|
+
> `ServiceTier = "flex"` via `ChatCompletionOptions` — veja `ai-agents-middleware-patterns`.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Decision
|
|
92
|
+
|
|
93
|
+
| Cenário | Service tier recomendado |
|
|
94
|
+
|---------|--------------------------|
|
|
95
|
+
| Chat com usuário aguardando na tela | `default` (ou `auto`) |
|
|
96
|
+
| Job async — relatório, enriquecimento, briefing | `flex` |
|
|
97
|
+
| Job de alta prioridade com SLA apertado | `priority` (disponibilidade depende do plano OpenAI da conta) |
|
|
98
|
+
| Batch API (24 h) | Não se aplica — Batch tem custo próprio |
|
|
99
|
+
|
|
100
|
+
> `auto` (padrão da API): OpenAI decide o tier baseado na carga. Use `flex` explícito
|
|
101
|
+
> quando você quer garantir o menor custo para trabalho assíncrono.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Anti-patterns
|
|
106
|
+
|
|
107
|
+
| Anti-pattern | Problema |
|
|
108
|
+
|-------------|----------|
|
|
109
|
+
| Usar `flex` em completion interativa | Latência imprevisível — usuário percebe lentidão |
|
|
110
|
+
| Usar `priority` (ou `default`) em batch noturno | Paga mais sem necessidade |
|
|
111
|
+
| Espalhar `ServiceTier = "flex"` por vários handlers | Usar middleware de ChatOptions para centralizar |
|
|
112
|
+
| Combinar flex tier com Batch API | São mecanismos distintos; não se somam |
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Checklist (verifiable by morph-eval)
|
|
117
|
+
|
|
118
|
+
- [ ] Tier flex usado somente em jobs assíncronos (Worker Service / Hangfire), nunca em handlers de request HTTP síncrono
|
|
119
|
+
- [ ] `ServiceTier` confirmado como string `"flex"` ou enum correto na versão do SDK instalada no projeto
|
|
120
|
+
- [ ] Jobs com flex tier não têm SLA de latência definido no contrato com o usuário final
|
|
121
|
+
- [ ] Se o agente usa `IChatClient` abstrato, o `ServiceTier` foi validado que é passado corretamente
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## References
|
|
126
|
+
|
|
127
|
+
- `ai-agents-setup` — packages e configuração do cliente OpenAI
|
|
128
|
+
- `ai-agents-batching` — alternativa de custo para volume alto de prompts independentes
|
|
129
|
+
- `ai-agents-middleware-patterns` (Onda 2) — middleware para injetar `ChatOptions` globalmente
|
|
130
|
+
- `ai-agents-providers-model-registry` — configuração provider-agnostic
|
|
131
|
+
- OpenAI Service Tiers: https://platform.openai.com/docs/guides/service-tiers
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
*MORPH-SPEC by Polymorphism Tech — ai-agents/service-tier-flex.md v1.0 (2026-05-19)*
|