@polymorphism-tech/morph-spec 8.34.2 → 8.35.1
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 +22 -5
- package/README.md +2 -2
- package/bin/morph-spec.js +18 -4
- package/bin/validate.js +379 -379
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +5 -4
- package/docs/QUICKSTART.md +1 -1
- package/framework/MORPH.md +16 -17
- package/framework/agents.json +197 -44
- package/framework/ai-pin.json +22 -0
- package/framework/commands/morph-media.md +45 -0
- package/framework/docs/CLI.md +236 -11
- package/framework/evals/proof-rubrics/README.md +76 -0
- package/framework/evals/proof-rubrics/eval-de-modelo.md +64 -0
- package/framework/evals/proof-rubrics/fiacao.md +54 -0
- package/framework/evals/proof-rubrics/guard-cego.md +52 -0
- package/framework/evals/proof-rubrics/media-claims.md +109 -0
- package/framework/evals/proof-rubrics/mutation-proof.md +77 -0
- package/framework/evals/proof-rubrics/observabilidade-genai.md +119 -0
- package/framework/evals/proof-rubrics/verde-nao-e-coberto.md +48 -0
- package/framework/evals/rubrics/architecture.md +30 -0
- package/framework/evals/rubrics/code-quality.md +26 -0
- package/framework/evals/rubrics/test-coverage.md +20 -0
- package/framework/hooks/claude-code/core/protect-spec-files.js +41 -4
- package/framework/hooks/claude-code/core/worktree-env-inject.js +43 -0
- 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/e2e-check.js +135 -22
- package/framework/hooks/shared/payload-utils.js +15 -2
- package/framework/hooks/shared/stdin-reader.js +26 -26
- package/framework/rules/ai-agents-standards.md +14 -2
- package/framework/schemas/ai-pin.schema.json +97 -0
- package/framework/schemas/config.schema.json +107 -0
- package/framework/schemas/feature.schema.json +23 -4
- package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
- package/framework/skills/core/morph-apply/SKILL.md +26 -5
- 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 +2 -2
- package/framework/skills/core/morph-implement/SKILL.md +18 -2
- package/framework/skills/core/morph-media/SKILL.md +215 -0
- package/framework/skills/core/morph-plan/SKILL.md +33 -2
- package/framework/skills/core/morph-proposal/SKILL.md +1 -1
- package/framework/skills/core/morph-review/SKILL.md +166 -9
- package/framework/skills/core/morph-stack-scan/SKILL.md +1 -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 +81 -3
- package/framework/standards/STANDARDS.json +1483 -839
- package/framework/standards/ai-agents/agent-archetypes.md +160 -0
- package/framework/standards/ai-agents/agent-session.md +164 -68
- package/framework/standards/ai-agents/agent-spec.md +196 -0
- package/framework/standards/ai-agents/batching.md +61 -37
- package/framework/standards/ai-agents/context-providers.md +97 -24
- package/framework/standards/ai-agents/conversational-agent-with-phases.md +239 -0
- package/framework/standards/ai-agents/cost-and-budget.md +256 -0
- package/framework/standards/ai-agents/durable-workflows-hitl.md +98 -5
- package/framework/standards/ai-agents/evals-with-cache.md +289 -0
- package/framework/standards/ai-agents/guardrails.md +222 -0
- package/framework/standards/ai-agents/llm-runtime-defaults.md +226 -0
- package/framework/standards/ai-agents/mcp-server.md +119 -18
- package/framework/standards/ai-agents/mcp-tools.md +85 -32
- package/framework/standards/ai-agents/media-pipeline.md +352 -0
- package/framework/standards/ai-agents/media-video.md +267 -0
- package/framework/standards/ai-agents/middleware-patterns.md +39 -5
- package/framework/standards/ai-agents/modalities-image-gen.md +354 -105
- package/framework/standards/ai-agents/modalities-speech-to-text.md +8 -2
- package/framework/standards/ai-agents/modalities-text-to-speech.md +10 -2
- package/framework/standards/ai-agents/modalities-vision.md +6 -2
- package/framework/standards/ai-agents/multi-agent-patterns.md +61 -5
- package/framework/standards/ai-agents/observability-patterns.md +227 -17
- package/framework/standards/ai-agents/production.md +38 -9
- package/framework/standards/ai-agents/prompt-sources.md +389 -0
- package/framework/standards/ai-agents/providers/model-registry.md +174 -39
- package/framework/standards/ai-agents/rag-custom-pgvector.md +69 -4
- package/framework/standards/ai-agents/service-tier-flex.md +27 -19
- package/framework/standards/ai-agents/setup.md +166 -50
- package/framework/standards/ai-agents/structured-output.md +34 -3
- package/framework/standards/ai-agents/sweet-spot.md +23 -3
- package/framework/standards/ai-agents/testing-ai.md +236 -0
- package/framework/standards/ai-agents/vector-data-extensions.md +50 -20
- package/framework/standards/ai-agents/workflows.md +27 -7
- package/framework/standards/frontend/design-system/ai-image-generation.md +12 -0
- package/framework/standards/frontend/design-system/ai-video-generation.md +13 -0
- package/framework/standards/infrastructure/docker/local-compose-isolation.md +3 -1
- 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/REGISTRY.json +13 -0
- 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 +1 -1
- 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 +1 -1
- 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/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/dotnet/ai-kit/Directory.Build.props +25 -0
- package/framework/templates/dotnet/ai-kit/Directory.Packages.props +26 -0
- package/framework/templates/dotnet/ai-kit/Morph.AiKit.sln +56 -0
- package/framework/templates/dotnet/ai-kit/NuGet.config +12 -0
- package/framework/templates/dotnet/ai-kit/README.md +128 -0
- package/framework/templates/dotnet/ai-kit/global.json +9 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentApi.cs +65 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactory.cs +289 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactoryOptions.cs +91 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpec.cs +91 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpecOptions.cs +181 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/AiKitAssemblyMarker.cs +14 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/ConversationStore.cs +174 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/IConversationStore.cs +54 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/InMemoryConversationStore.cs +75 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/CountingChatClient.cs +71 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalAssertion.cs +246 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheMissException.cs +57 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheOptions.cs +78 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheStamp.cs +225 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalFixture.cs +463 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalMode.cs +32 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalQualityEvaluators.cs +49 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalScenario.cs +214 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalSummary.cs +168 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/OfflineChatClient.cs +142 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/ShortPathResponseCache.cs +349 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaGenerator.cs +42 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaProvider.cs +77 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaArtifact.cs +28 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaDisclosure.cs +107 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaGenerator.cs +253 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaIdempotencyKey.cs +103 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJob.cs +259 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobId.cs +21 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobState.cs +47 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaPricing.cs +102 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaProvenance.cs +44 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaRequest.cs +192 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaResult.cs +94 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaReview.cs +99 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaSeams.cs +97 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaStore.cs +133 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MorphMedia.cs +93 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/GoogleImageProvider.cs +112 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/OpenAIImageProvider.cs +288 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/VeoVideoProvider.cs +158 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/IUsageCostSink.cs +29 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostMiddleware.cs +208 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostRecord.cs +95 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Morph.AiKit.csproj +38 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphOpenTelemetryExtensions.cs +119 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphTelemetryOptions.cs +82 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/IProviderClientFactory.cs +33 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelAlias.cs +267 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelRegistry.cs +474 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/model-registry.v2.json +87 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs +169 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaPlan.cs +49 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentFactoryTests.cs +495 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentSpecTests.cs +260 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ConversationStoreTests.cs +405 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/DeltaIngestTests.cs +379 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalAssertionTests.cs +197 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheMissTests.cs +139 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheStampTests.cs +157 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFailuresTests.cs +178 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFixtureTests.cs +153 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalRefreshTests.cs +194 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalWorkspace.cs +86 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/KitEvals.cs +213 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/OfflineChatClientTests.cs +95 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClient.cs +225 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClientTests.cs +215 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeClock.cs +33 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeMediaProvider.cs +89 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeProviderClientFactory.cs +55 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeUsageCostSink.cs +60 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/InMemoryMediaStore.cs +131 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAccessibilityTests.cs +133 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAliasIsNotAnAgentTests.cs +127 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +216 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaGeneratorTests.cs +264 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaIdempotencyKeyTests.cs +148 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaJobStateTests.cs +184 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaReviewTests.cs +89 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaStoreTests.cs +98 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ModelRegistryTests.cs +451 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Morph.AiKit.Tests.csproj +76 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/SkeletonSmokeTests.cs +33 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/TelemetryTests.cs +261 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/UsageCostMiddlewareTests.cs +374 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/.morph-eval-cache.json +12 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/orcamento/acme/a-resposta-estruturada.json +24 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/a-saudacao.json +23 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/b-escalonamento.json +24 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/globex/a-saudacao.json +23 -0
- 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 +3 -3
- package/src/commands/dashboard/dashboard.js +53 -53
- package/src/commands/e2e/e2e.js +15 -2
- package/src/commands/index.js +13 -13
- package/src/commands/project/checkpoint.js +209 -209
- package/src/commands/project/doctor.js +148 -6
- package/src/commands/project/update.js +469 -153
- package/src/commands/project/worktree.js +76 -4
- package/src/commands/state/advance.js +24 -2
- package/src/commands/state/approve.js +33 -1
- package/src/commands/state/create.js +72 -11
- package/src/commands/state/finish.js +379 -24
- package/src/commands/state/gate-check.js +190 -6
- package/src/commands/state/score.js +36 -1
- package/src/commands/validation/verify.js +134 -25
- package/src/core/state/phase-state-machine.js +197 -197
- package/src/core/state/state-manager.js +9 -1
- 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/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/ai/ai-checks.js +182 -0
- package/src/lib/ai/ai-project-scan.js +347 -0
- package/src/lib/ai/code-audit.js +181 -0
- package/src/lib/ai/comment-stripper.js +184 -0
- package/src/lib/ai/pin-drift.js +138 -0
- package/src/lib/ai/registry-audit.js +285 -0
- package/src/lib/detectors/design-system-detector.js +188 -188
- package/src/lib/detectors/index.js +217 -217
- package/src/lib/e2e/compose-env.js +50 -4
- package/src/lib/evaluator-report.js +269 -15
- package/src/lib/generators/design-system-generator.js +508 -508
- package/src/lib/generators/settings-generator.js +209 -209
- package/src/lib/git/default-branch.js +92 -4
- package/src/lib/git/pr-files.js +56 -0
- package/src/lib/hooks/hook-executor.js +167 -167
- package/src/lib/installers/effects.js +193 -0
- package/src/lib/installers/mcp-installer.js +719 -719
- package/src/lib/installers/templates-reconcile.js +3 -3
- package/src/lib/risk-detector.js +284 -0
- package/src/lib/standards/verified-against.js +276 -0
- package/src/lib/tasks/eval-node.js +485 -0
- package/src/lib/tasks/linux-runner.js +297 -0
- package/src/lib/tasks/task-classifier.js +30 -30
- package/src/lib/tasks/task-parser.js +209 -209
- package/src/lib/tasks/test-nodes.js +486 -0
- package/src/lib/tasks/test-runner.js +410 -33
- package/src/lib/validators/checkpoint-persistence.js +39 -39
- package/src/lib/validators/css/css-validator.js +340 -340
- 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/verify-runner.js +583 -28
- package/src/lib/worktree/docker-audit.js +287 -0
- package/src/lib/worktree/env-allocator.js +24 -0
- package/src/lib/worktree/worktree-audit.js +30 -1
- package/src/scripts/setup-infra.js +24 -11
- package/src/utils/agent-id-mapper.js +11 -11
- package/src/utils/agents-installer.js +18 -8
- package/src/utils/claude-md-injector.js +10 -5
- package/src/utils/claude-settings-manager.js +300 -300
- package/src/utils/file-copier.js +11 -4
- package/src/utils/hooks-installer.js +29 -26
- package/src/utils/skills-installer.js +36 -29
- package/src/utils/version-checker.js +68 -3
- package/framework/standards/ai-agents/prompts-in-db.md +0 -214
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
> **Scope:** stacks=["dotnet"]
|
|
4
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
|
|
5
|
+
> **Keywords:** model registry, provider agnostic, model alias, IChatClient factory, multi-model, model selection, model config, api per alias, responses vs chat, reasoning effort
|
|
6
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
7
|
|
|
8
|
-
**Verified against:**
|
|
8
|
+
**Verified against:** Microsoft.Agents.AI 1.20.0 + Microsoft.Extensions.AI 10.9.0 + OpenAI 2.13.0 (ai-pin 2026-09-08); provado por `templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelRegistry.cs` e `.../Providers/ModelAlias.cs` e `.../Agents/AgentApi.cs`. Nomes de tipo do `Microsoft.Extensions.AI` e do `OpenAI` medidos por reflexão sobre as assemblies do pin em 2026-09-08. Last-verified: 2026-09-08.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
## Pattern
|
|
13
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.
|
|
14
|
+
The project consuming morph-spec maintains a **single JSON file** mapping aliases (`text-default`, `vision`, `reasoning`, etc.) to `{ provider, model, api, options }`. Agents reference aliases — never hardcoded model strings. Switching provider or model is a one-file change.
|
|
15
15
|
|
|
16
16
|
```
|
|
17
17
|
Standard (this file, in framework) — explains the pattern + canonical schema
|
|
@@ -28,17 +28,38 @@ Project (consumer) — config/model-registry.json + src/.../ModelRegistry.cs
|
|
|
28
28
|
// config/model-registry.json — IN THE PROJECT (not in framework)
|
|
29
29
|
{
|
|
30
30
|
"$schema": "./model-registry.schema.json",
|
|
31
|
-
"version": "
|
|
31
|
+
"version": "2.0",
|
|
32
32
|
"defaultAlias": "text-default",
|
|
33
33
|
"aliases": {
|
|
34
|
-
|
|
35
|
-
"text-
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
// `api` omitted → "responses" (the house default; see §API per alias)
|
|
35
|
+
"text-default": { "provider": "openai", "model": "gpt-4o-mini", "options": { "temperature": 0.7 } },
|
|
36
|
+
"text-heavy": { "provider": "openai", "model": "gpt-4o", "options": { "temperature": 0.5 } },
|
|
37
|
+
|
|
38
|
+
// Reasoning alias: NO temperature. See §temperature × reasoning.
|
|
39
|
+
"reasoning": {
|
|
40
|
+
"provider": "openai",
|
|
41
|
+
"model": "gpt-5.5",
|
|
42
|
+
"api": "responses",
|
|
43
|
+
"options": { "reasoningEffort": "medium" }
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
// Chat Completions is opt-in, in writing, with the constraint declared.
|
|
47
|
+
"legacy-chat": {
|
|
48
|
+
"provider": "openai",
|
|
49
|
+
"model": "gpt-5.5",
|
|
50
|
+
"api": "chat",
|
|
51
|
+
"options": {},
|
|
52
|
+
"constraints": {
|
|
53
|
+
"toolCallingRequiresReasoningEffortNone": true,
|
|
54
|
+
"provenance": "developers.openai.com/api/docs/guides/migrate-to-responses, lido 2026-09-08"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
"long-form": { "provider": "anthropic", "model": "claude-sonnet-4-6", "options": {} },
|
|
59
|
+
"vision": { "provider": "google", "model": "gemini-2.5-flash", "options": {} },
|
|
60
|
+
"embeddings": { "provider": "openai", "model": "text-embedding-3-small", "options": { "dimensions": 1536 } },
|
|
61
|
+
"transcription": { "provider": "openai", "model": "whisper-1", "options": {} },
|
|
62
|
+
"local-dev": { "provider": "ollama", "model": "llama3.2:3b", "options": { "endpoint": "http://localhost:11434/v1" } }
|
|
42
63
|
},
|
|
43
64
|
"fallback": {
|
|
44
65
|
"text-default": "anthropic/claude-haiku-4-5",
|
|
@@ -52,27 +73,126 @@ Project (consumer) — config/model-registry.json + src/.../ModelRegistry.cs
|
|
|
52
73
|
**Field semantics:**
|
|
53
74
|
- `provider`: SDK family — one of `openai`, `google`, `anthropic`, `ollama` (first-class). `azure-openai` is supported as an opt-in branch (see §providers).
|
|
54
75
|
- `model`: model id for that provider.
|
|
55
|
-
- `
|
|
76
|
+
- `api`: **the protocol this alias speaks** — `responses` or `chat`. Omitting it means `responses`. See §API per alias.
|
|
77
|
+
- `options`: per-request extras. `temperature`, `topP`, `maxOutputTokens`, `seed`, `stopSequences`, `toolMode`, `reasoningEffort`, `serviceTier`, plus `endpoint` for Ollama. **`temperature` and `reasoningEffort` never appear in the same alias** — see §temperature × reasoning.
|
|
78
|
+
- `constraints`: declared limits of this alias (`toolCallingRequiresReasoningEffortNone`, `temperatureUnsupported`) — **each one requires `provenance`**, the document and date it came from. A limit with no source is folklore with the force of code.
|
|
56
79
|
- `fallback`: when the primary provider fails (rate limit, outage), switch to this alias. Format `provider/model`.
|
|
57
80
|
|
|
58
81
|
---
|
|
59
82
|
|
|
83
|
+
## API per alias — `responses` vs `chat`
|
|
84
|
+
|
|
85
|
+
**Every alias declares which protocol it speaks.** This is the field the v1 schema did not have, and its absence is why "which API does this agent talk to?" used to be answered by reading a conditional in the middle of the client factory.
|
|
86
|
+
|
|
87
|
+
| Value | Meaning | When |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| `responses` (**default when omitted**) | OpenAI **Responses API** | New work. `default(AgentApi)` is `Responses` on purpose |
|
|
90
|
+
| `chat` | OpenAI **Chat Completions** | Opt-in, written by a human, for broad model compatibility or an existing integration |
|
|
91
|
+
|
|
92
|
+
**Why Responses is the default**, in two documented facts:
|
|
93
|
+
|
|
94
|
+
1. Microsoft Learn, *Agent Framework → model providers → OpenAI* (`ms.date` 2026-09-03), verbatim: *"Responses is the recommended primary client when available"*, with a tool matrix in which Chat Completions loses **Code Interpreter, File Search and Hosted MCP**.
|
|
95
|
+
2. OpenAI, *Migrate to the Responses API* (developers.openai.com/api/docs/guides/migrate-to-responses, lido 2026-09-08), verbatim: *"While Chat Completions remains supported, Responses is recommended for all new projects."*
|
|
96
|
+
|
|
97
|
+
**Providers that expose a single protocol (Google, Ollama, Anthropic) ignore the field.** The enum describes the choice **between the two OpenAI protocols**; writing `"api": "chat"` on an Ollama alias would suggest a choice that provider does not offer. They therefore omit `api` and fall into `responses`, which the registry treats as "no protocol decision to make here". What must **not** happen is reaching an OpenAI-compatible endpoint (Ollama, gateway) through the Responses path: the Responses API is OpenAI's, not the compatible protocol's — the provider branch in `ModelRegistry.GetChatClient` builds a Chat Completions client for those, regardless of the field.
|
|
98
|
+
|
|
99
|
+
> Measured: `Morph.AiKit.Agents.AgentApi` has `Responses = 0` so that `default(AgentApi)` is Responses, and `ModelRegistry.ReadApi` returns `AgentApi.Responses` when `api` is absent and throws naming the alias for any value other than `responses`/`chat`. `AgentSpec.ResolveApi(aliasApi) => Api ?? aliasApi` keeps the precedence between spec and registry in exactly one place.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## temperature × reasoning — mutually exclusive per alias
|
|
104
|
+
|
|
105
|
+
**Rule:** an alias that carries `reasoningEffort` does **not** carry `temperature`. The rule has **two different origins, and the standard labels each one** — because they do not carry the same weight.
|
|
106
|
+
|
|
107
|
+
### Origin 1 — documented
|
|
108
|
+
|
|
109
|
+
OpenAI, *Migrate to the Responses API* (developers.openai.com/api/docs/guides/migrate-to-responses, lido 2026-09-08), verbatim:
|
|
110
|
+
|
|
111
|
+
> *"Starting with GPT-5.4, Chat Completions does not support tool calling with `reasoning_effort` values other than `none`."*
|
|
112
|
+
|
|
113
|
+
Read it narrowly, because it **is** narrow: the restriction needs **four** facts at once — protocol `chat`, tools present, an effort actually sent, and that effort ≠ `none`. It is *not* "reasoning models reject tools". Direct consequence: **a reasoning alias that uses tools needs `api: responses`.**
|
|
114
|
+
|
|
115
|
+
### Origin 2 — measured in the field, no primary source
|
|
116
|
+
|
|
117
|
+
*"Reasoning models reject `temperature != 1` when tools are present."* This is **measured in production**, not documented: GHLBrain's `ToolAgentRunner.cs:35-38` strips temperature for that path, recorded in `docs/specs/elevacao-9/brutos/scan-ghlbrain.md:106`, and corroborated by third parties (issues on `openai-python` and LibreChat). **The 2026-09-08 research did not find a primary OpenAI sentence stating it.**
|
|
118
|
+
|
|
119
|
+
So it lives in the schema as a **per-alias flag with mandatory provenance** (`constraints.temperatureUnsupported` + `constraints.provenance`), never as a universal rule hardcoded in the registry. Whoever turns it on is asserting it for one specific model and writing where they got it from.
|
|
120
|
+
|
|
121
|
+
> Measured: `ModelAliasConstraints.ValidateProvenance` refuses to load an alias with a flag set and no `provenance`, and `ModelAlias.CheckRequest` returns a Result (never an exception) listing each violation **with its provenance attached**.
|
|
122
|
+
|
|
123
|
+
### Reasoning effort values, by model, dated
|
|
124
|
+
|
|
125
|
+
| Model | Accepted efforts | Source (lido 2026-09-08) |
|
|
126
|
+
|---|---|---|
|
|
127
|
+
| `gpt-5.5` | `none`, `low`, `medium` (default), `high`, `xhigh` | developers.openai.com/api/docs/models/gpt-5.5 |
|
|
128
|
+
| `gpt-5.6` | the above **plus `max`**, and introduces `reasoning.mode` (`standard` / `pro`) | developers.openai.com/api/docs/guides/latest-model?model=gpt-5.6 |
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## How this reaches .NET
|
|
133
|
+
|
|
134
|
+
**The native path is confirmed** — measured by reflection over `Microsoft.Extensions.AI.Abstractions` 10.9.0 on 2026-09-08, and compiled by the ai-kit:
|
|
135
|
+
|
|
136
|
+
```csharp
|
|
137
|
+
// Microsoft.Extensions.AI 10.9.0 — measured surface
|
|
138
|
+
// ChatOptions.Reasoning : ReasoningOptions?
|
|
139
|
+
// ReasoningOptions { ReasoningEffort? Effort; ReasoningOutput? Output; }
|
|
140
|
+
// enum ReasoningEffort { None=0, Low=1, Medium=2, High=3, ExtraHigh=4 }
|
|
141
|
+
var options = new ChatOptions
|
|
142
|
+
{
|
|
143
|
+
ModelId = alias.Model,
|
|
144
|
+
Reasoning = new ReasoningOptions { Effort = ReasoningEffort.Medium },
|
|
145
|
+
};
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Escape hatch, and when it is still needed.** The M.E.AI enum has five members; the provider's own ladder is wider (`gpt-5.6` adds `max`, and `reasoning.mode`). For a value the enum cannot express, go through `ChatOptions.RawRepresentationFactory` and the provider type:
|
|
149
|
+
|
|
150
|
+
```csharp
|
|
151
|
+
// OpenAI 2.13.0 — measured surface
|
|
152
|
+
// CreateResponseOptions.ReasoningOptions : ResponseReasoningOptions
|
|
153
|
+
// ResponseReasoningOptions.ReasoningEffortLevel : ResponseReasoningEffortLevel?
|
|
154
|
+
// ResponseReasoningEffortLevel = { None, Minimal, Low, Medium, High } ← no xhigh/max in 2.13.0
|
|
155
|
+
#pragma warning disable OPENAI001 // still required — see §OPENAI001
|
|
156
|
+
options.RawRepresentationFactory = _ => new CreateResponseOptions
|
|
157
|
+
{
|
|
158
|
+
ReasoningOptions = new ResponseReasoningOptions
|
|
159
|
+
{
|
|
160
|
+
ReasoningEffortLevel = ResponseReasoningEffortLevel.High,
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
#pragma warning restore OPENAI001
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Honest limit:** `xhigh` and `max` are documented by OpenAI for `gpt-5.5`/`gpt-5.6` but are **not present in the `OpenAI` 2.13.0 SDK's `ResponseReasoningEffortLevel`** (measured). Sending them today means a raw JSON patch, not a typed member. Confirm against the installed package before promising a project the wider ladder.
|
|
167
|
+
|
|
168
|
+
### `OPENAI001`
|
|
169
|
+
|
|
170
|
+
**Measured, not inferred:** `OpenAI.Responses.ResponsesClient` and `OpenAI.Responses.CreateResponseOptions` still carry `[Experimental("OPENAI001")]` in **OpenAI 2.13.0** (reflection over the pinned assembly, 2026-09-08). Code that touches the Responses client types directly still needs `#pragma warning disable OPENAI001` (or `<NoWarn>OPENAI001</NoWarn>`). `OpenAI.Chat.ChatClient` carries no such attribute.
|
|
171
|
+
|
|
172
|
+
Going through `Microsoft.Extensions.AI` (`IChatClient`) or the MAF (`AIAgent`) keeps the diagnostic out of project code — the bridge package absorbs it. That is a reason to prefer the abstraction, not merely a style preference.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
60
176
|
## Providers (first-class)
|
|
61
177
|
|
|
62
178
|
> **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
179
|
|
|
64
|
-
| Provider | `provider` value | NuGet SDK (
|
|
65
|
-
|
|
66
|
-
| **OpenAI** | `openai` | `OpenAI` 2
|
|
67
|
-
| **Ollama** | `ollama` | `OpenAI` 2
|
|
68
|
-
| **Google Gemini** | `google` |
|
|
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`
|
|
180
|
+
| Provider | `provider` value | NuGet SDK (apurado 2026-09-08) | `api` | Notes |
|
|
181
|
+
|----------|------------------|-------------------------------|-------|-------|
|
|
182
|
+
| **OpenAI** | `openai` | `OpenAI` **2.13.0** (pin) + `Microsoft.Extensions.AI.OpenAI` **10.9.0** (fora do pin, apurado 2026-09-08) | `responses` (default) / `chat` | `new OpenAIClient(key).GetResponsesClient().AsIChatClient("<model>")` |
|
|
183
|
+
| **Ollama** | `ollama` | `OpenAI` **2.13.0** (OpenAI-compatible endpoint) | ignora o campo | Same `ChatClient` with custom `Endpoint` + dummy key. **Never** through the Responses path |
|
|
184
|
+
| **Google Gemini** | `google` | `Google.GenAI` **1.21.0** (pin) | ignora o campo | Adapt provider client to `IChatClient` |
|
|
185
|
+
| **Anthropic Claude** | `anthropic` | Confirm current SDK on NuGet before use | ignora o campo | Adapt provider client to `IChatClient` |
|
|
186
|
+
| **Azure OpenAI** (opt-in, not default) | `azure-openai` | `Azure.AI.OpenAI` + `Azure.Identity` — confirm exact versions on NuGet before use | segue o OpenAI | Add only when a client requires data residency |
|
|
187
|
+
|
|
188
|
+
> **Restore trap, measured 2026-09-08:** `Microsoft.Extensions.AI.OpenAI` 10.9.0 declares `OpenAI (>= 2.12.0 && < 2.13.0)`. Pairing it with the pinned `OpenAI` 2.13.0 emits **NU1608** on restore. Either pin `OpenAI` to 2.12.x alongside the bridge, or accept the warning knowingly and write the decision in `decisions.md`. Do not discover this in CI.
|
|
189
|
+
|
|
190
|
+
**No floating ranges.** Every `PackageReference` above is an exact version. A floating `2.*` on a weekly-cadence SDK is how ProspectPRO bought a `MissingMethodException` on the Responses API **after paying for the call** (`docs/specs/elevacao-9/brutos/scan-prospectpro.md:55`).
|
|
71
191
|
|
|
72
192
|
**Adding a provider branch:** the `ModelRegistry.cs` template implements `openai` + `ollama`. To add `google`, `anthropic`, or `azure-openai`:
|
|
73
193
|
1. Confirm the current NuGet SDK — community SDKs evolve; check NuGet/context7 before coding.
|
|
74
194
|
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
|
|
195
|
+
3. Add the SDK `PackageReference` to the project's `.csproj`, with an **exact** version.
|
|
76
196
|
4. The branch returns an `IChatClient`. If the SDK doesn't expose `IChatClient` natively, wrap it with an adapter.
|
|
77
197
|
|
|
78
198
|
**Direct models only:** never use a hosted agent service. Every provider above is reached as a direct model.
|
|
@@ -82,17 +202,21 @@ Project (consumer) — config/model-registry.json + src/.../ModelRegistry.cs
|
|
|
82
202
|
## Implementation pattern
|
|
83
203
|
|
|
84
204
|
```csharp
|
|
85
|
-
// WRONG — hardcoded model + provider
|
|
205
|
+
// WRONG — hardcoded model + provider, and no protocol decision anywhere
|
|
86
206
|
var agent = new ChatClient("gpt-4o-mini", apiKey)
|
|
87
207
|
.AsIChatClient()
|
|
88
208
|
.AsAIAgent(instructions: prompt);
|
|
89
209
|
|
|
90
|
-
// RIGHT — alias-based, provider-agnostic
|
|
210
|
+
// RIGHT — alias-based, provider-agnostic; the alias carries provider, model AND api
|
|
91
211
|
var agent = _modelRegistry.GetChatClient("text-default")
|
|
92
212
|
.AsAIAgent(instructions: prompt);
|
|
93
213
|
```
|
|
94
214
|
|
|
95
|
-
The `ModelRegistry` class in the project owns the mapping. See template `templates/code/dotnet/ai-agents/ModelRegistry.cs.template
|
|
215
|
+
The `ModelRegistry` class in the project owns the mapping. See template `templates/code/dotnet/ai-agents/ModelRegistry.cs.template`, and the compiling reference implementation in `templates/dotnet/ai-kit/src/Morph.AiKit/Providers/`.
|
|
216
|
+
|
|
217
|
+
**One client per alias, memoized.** A provider client owns a connection pool and an HTTP handler; rebuilding it per call is how socket exhaustion usually starts. `ModelRegistry.GetChatClient` calls the factory once per alias and hands back the same instance afterwards.
|
|
218
|
+
|
|
219
|
+
**Failure at load time, never as control flow.** Invalid document, alias with no pricing decision, constraint without provenance: all of it throws during composition, naming the alias and the field — never as a null that crosses three layers and shows up as a zeroed cost in a report.
|
|
96
220
|
|
|
97
221
|
---
|
|
98
222
|
|
|
@@ -102,26 +226,26 @@ When a task says "register the X agent" and the project has >1 model or >1 provi
|
|
|
102
226
|
|
|
103
227
|
1. Read this standard.
|
|
104
228
|
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
|
|
229
|
+
3. Copy `templates/code/dotnet/ai-agents/model-registry.json.template` to `config/model-registry.json`. Adjust aliases to project needs, and **declare `api` on every OpenAI alias that is not Responses**.
|
|
106
230
|
4. Wire `ModelRegistry` into DI (see `AgentBootstrap.cs.template`).
|
|
107
231
|
5. Future agents reference `_modelRegistry.GetChatClient(alias)`.
|
|
108
232
|
|
|
109
233
|
---
|
|
110
234
|
|
|
111
|
-
## Recommended aliases & models (orientativo —
|
|
235
|
+
## Recommended aliases & models (orientativo — setembro/2026)
|
|
112
236
|
|
|
113
237
|
> Tabela orientativa. Actual values live in the project's `model-registry.json`. Models evolve fast.
|
|
114
238
|
|
|
115
|
-
| Alias | Provider sugerido | Modelo (
|
|
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 |
|
|
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 |
|
|
239
|
+
| Alias | Provider sugerido | Modelo (setembro/2026) | `api` | Use case |
|
|
240
|
+
|-------|-------------------|------------------------|-------|----------|
|
|
241
|
+
| `text-default` | openai | gpt-4o-mini | responses | Geração padrão de texto |
|
|
242
|
+
| `text-heavy` | openai / anthropic | gpt-4o / claude-sonnet-4-6 | responses | Análise complexa |
|
|
243
|
+
| `reasoning` | openai | gpt-5.5 (`reasoningEffort`, **sem** `temperature`) | responses | Decisões, planejamento, math |
|
|
244
|
+
| `long-form` | anthropic | claude-sonnet-4-6 | — | Escrita longa, análise de documento |
|
|
245
|
+
| `vision` | google / openai | gemini-2.5-flash / gpt-4o | responses | Image → Text |
|
|
246
|
+
| `embeddings` | openai | text-embedding-3-small | — | RAG, similarity |
|
|
247
|
+
| `transcription` | openai | whisper-1 | — | Audio → Text |
|
|
248
|
+
| `local-dev` | ollama | llama3.2:3b | — (Chat Completions no fio) | Dev local, sem custo |
|
|
125
249
|
|
|
126
250
|
---
|
|
127
251
|
|
|
@@ -130,6 +254,10 @@ When a task says "register the X agent" and the project has >1 model or >1 provi
|
|
|
130
254
|
| Anti-pattern | Why | Right way |
|
|
131
255
|
|--------------|-----|-----------|
|
|
132
256
|
| Hardcode `"gpt-4o-mini"` in agent code | Switching model = grep + replace | Use `_modelRegistry.GetChatClient("text-default")` |
|
|
257
|
+
| Alias com `temperature` **e** `reasoningEffort` | Os dois não convivem no mesmo modelo; um dos dois será silenciosamente ignorado ou rejeitado | Um alias de raciocínio sem `temperature`; se o limite for do modelo, declare em `constraints` **com `provenance`** |
|
|
258
|
+
| `constraints` sem `provenance` | Um limite sem fonte é folclore com força de código | Escreva o documento e a data; o registry recusa a carga sem isso |
|
|
259
|
+
| Alias OpenAI sem decidir `api` quando o caminho é Chat Completions | Ninguém sabe qual protocolo o agente fala até ler o factory | Omitido = `responses`; Chat Completions exige `"api": "chat"` por escrito |
|
|
260
|
+
| `PackageReference` com faixa flutuante (`2.*`, `1.0.*`) | SDK de cadência semanal quebra em produção depois de a chamada ser paga | Versão exata; pacote fora do `ai-pin.json` leva a data de apuração |
|
|
133
261
|
| 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
262
|
| Different `ModelRegistry` class per agent | Defeats the purpose | One class per project, singleton in DI |
|
|
135
263
|
| Use a hosted agent service to "simplify" | Hosted lags 6-9 months, removes control | Always direct models |
|
|
@@ -139,20 +267,27 @@ When a task says "register the X agent" and the project has >1 model or >1 provi
|
|
|
139
267
|
|
|
140
268
|
## Checklist (verifiable by morph-eval)
|
|
141
269
|
|
|
142
|
-
- [ ] Project has `config/model-registry.json` (or declared equivalent).
|
|
270
|
+
- [ ] Project has `config/model-registry.json` (or declared equivalent), `version` `2.0`.
|
|
143
271
|
- [ ] Project has a `ModelRegistry` class registered as singleton in DI.
|
|
272
|
+
- [ ] Every OpenAI alias either omits `api` (→ `responses`) or declares `"api": "chat"` explicitly.
|
|
273
|
+
- [ ] No alias carries `temperature` and `reasoningEffort` at the same time.
|
|
274
|
+
- [ ] Every `constraints` block has a non-empty `provenance` with a document and a date.
|
|
144
275
|
- [ ] No agent code has hardcoded model strings — `grep -rE 'gpt-[0-9]|claude-|gemini-|whisper-' src/` matches only `ModelRegistry.cs`.
|
|
145
276
|
- [ ] Aliases used in agent code exist in `model-registry.json`.
|
|
277
|
+
- [ ] No `PackageReference` in the project uses a floating range for an AI SDK.
|
|
146
278
|
|
|
147
279
|
---
|
|
148
280
|
|
|
149
281
|
## References
|
|
150
282
|
|
|
151
|
-
- `ai-agents-setup` — provider SDKs
|
|
283
|
+
- `ai-agents-setup` — provider SDKs, Responses vs Chat Completions setup
|
|
284
|
+
- `ai-agents-structured-output` — `ResponseFormat` and what else goes into `ChatOptions`
|
|
285
|
+
- `ai-agents-service-tier-flex` — `serviceTier` in `options`
|
|
286
|
+
- Reference implementation (compiles against the pin): `templates/dotnet/ai-kit/src/Morph.AiKit/Providers/`
|
|
152
287
|
- Template: `templates/code/dotnet/ai-agents/ModelRegistry.cs.template`
|
|
153
288
|
- Template: `templates/code/dotnet/ai-agents/model-registry.json.template`
|
|
154
289
|
- Template: `templates/code/dotnet/ai-agents/AgentBootstrap.cs.template`
|
|
155
290
|
|
|
156
291
|
---
|
|
157
292
|
|
|
158
|
-
*MORPH-SPEC by Polymorphism Tech — ai-agents/providers/model-registry.md
|
|
293
|
+
*MORPH-SPEC by Polymorphism Tech — ai-agents/providers/model-registry.md v2.0 (2026-09-08)*
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
> **Scope:** stacks=["dotnet"]
|
|
4
4
|
> **Layer:** 1 (on-keyword)
|
|
5
|
-
> **Keywords:** rag, vector search, pgvector, embeddings, custom rag, retrieval, semantic search, knowledge base, RAG tool
|
|
5
|
+
> **Keywords:** rag, vector search, pgvector, embeddings, custom rag, retrieval, semantic search, knowledge base, RAG tool, delta ingestion, incremental ingestion, lookup key
|
|
6
6
|
> **Read by Claude in:** implement (when an agent needs to retrieve knowledge)
|
|
7
7
|
|
|
8
|
-
**Verified against:**
|
|
8
|
+
**Verified against:** Microsoft.Agents.AI 1.20.0 + Microsoft.Extensions.AI 10.9.0 (ai-pin 2026-09-08); `provado por templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs` **restrito à seção "Ingestão delta por lookup-key"** — é a única parte deste standard que o ai-kit compila. Todo o resto (pgvector, SQL, HNSW, embeddings, multi-tenant) é **verificação documental**; a versão e o status de `Microsoft.Extensions.DataIngestion` foram apurados no nuget.org em 2026-09-08. Last-verified: 2026-09-08.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -186,6 +186,65 @@ The agent decides autonomously when to call `VectorSearchTool.SearchAsync`. It r
|
|
|
186
186
|
|
|
187
187
|
---
|
|
188
188
|
|
|
189
|
+
## Ingestão delta por lookup-key
|
|
190
|
+
|
|
191
|
+
**O defeito que esta seção existe para matar está em produção e foi medido.** `KbStore.IngestAsync` do GHLBrain faz `DELETE … WHERE location_id AND source` e re-insere/re-embeda **tudo** numa transação (`docs/specs/elevacao-9/brutos/scan-ghlbrain.md:412`): 288 itens re-embedados a cada republish do catálogo, e uma **janela** entre o apagar e o gravar em que a busca não acha nada.
|
|
192
|
+
|
|
193
|
+
### O contrato — uma função pura, sem I/O
|
|
194
|
+
|
|
195
|
+
```csharp
|
|
196
|
+
// Nada aqui toca banco, vetor ou arquivo. Quem APLICA o plano é o projeto,
|
|
197
|
+
// que sabe qual é a sua transação — e é por isso que a idempotência da
|
|
198
|
+
// ingestão pode ser provada sem subir infraestrutura nenhuma.
|
|
199
|
+
public static DeltaPlan<T> Plan<T>(
|
|
200
|
+
IEnumerable<T> incoming,
|
|
201
|
+
Func<T, string> lookupKey,
|
|
202
|
+
Func<T, string> contentHash,
|
|
203
|
+
IReadOnlyDictionary<string, string> existingHashes);
|
|
204
|
+
|
|
205
|
+
public sealed record DeltaPlan<T>(
|
|
206
|
+
IReadOnlyList<T> Added, // chave não existia no acervo
|
|
207
|
+
IReadOnlyList<T> Updated, // chave existia com OUTRO conteúdo
|
|
208
|
+
IReadOnlyList<string> Removed, // chaves no acervo que NÃO vieram na entrada — são chaves, não itens
|
|
209
|
+
IReadOnlyList<T> Unchanged) // chave existia com o MESMO conteúdo
|
|
210
|
+
{
|
|
211
|
+
public bool IsNoOp => Added.Count == 0 && Updated.Count == 0 && Removed.Count == 0;
|
|
212
|
+
public int WriteCount => Added.Count + Updated.Count + Removed.Count;
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
`IsNoOp` **é a idempotência expressa como predicado**: replanejar a mesma entrada sobre o acervo que ela produziu tem de dar `true`. É o teste que separa "delta" de "delete-and-reinsert com passos extras".
|
|
217
|
+
|
|
218
|
+
### As quatro regras que fazem o delta valer a pena
|
|
219
|
+
|
|
220
|
+
1. **`Unchanged` não é re-embedado.** É a economia inteira. Num republish típico a lista grande é `Unchanged` e as outras três são curtas — e é exatamente isso que a ingestão anterior escondia.
|
|
221
|
+
2. **`Removed` são as chaves presentes no acervo e ausentes do `incoming`.** Sem esse balde, conteúdo apagado na origem continua sendo devolvido pela busca.
|
|
222
|
+
3. **O id continua determinístico** — `DeterministicUuid.V5(namespace, "{loc}:{source}:{idx}")` já é a prática — para que `Updated` seja **upsert**, não delete+insert. Delete+insert quebra referências e troca o id de um chunk que só mudou de texto.
|
|
223
|
+
4. **Sem janela vazia: nunca apague tudo antes de gravar.** É literalmente o que faz a busca devolver vazio durante a reingestão. Aplique `Added`/`Updated` primeiro e só então `Removed`, dentro da mesma transação.
|
|
224
|
+
|
|
225
|
+
### Chave duplicada no `incoming` é erro de entrada
|
|
226
|
+
|
|
227
|
+
Duas linhas com a mesma lookup-key tornam o plano **não determinístico** (qual das duas vence?). O planejador **falha**, dizendo a chave e **as duas posições** em que ela apareceu — porque "chave X duplicada" sem posição manda procurar num corpus inteiro. Silenciar isso produz um acervo diferente a cada execução da mesma entrada.
|
|
228
|
+
|
|
229
|
+
### A alternativa oficial, com o status honesto
|
|
230
|
+
|
|
231
|
+
`Microsoft.Extensions.DataIngestion` é o pipeline oficial (`IngestionDocument` → `IngestionChunker<T>` → `VectorStoreWriter<T>`), com `VectorStoreWriterOptions.IncrementalIngestion` e deduplicação por `DocumentId`. Status apurado em 2026-09-08: **preview** — a versão mais recente no nuget.org é `10.9.0-preview.1.26411.16`, e **não existe versão estável**.
|
|
232
|
+
|
|
233
|
+
**Ressalva medida, que muda a decisão:** o teste oficial da funcionalidade chama-se `IncrementalIngestion_WithManyRecords_DeletesAllPreExistingChunks`. A semântica é *apagar todos os chunks pré-existentes daquele documento antes de regravar* — o que **não** é o mesmo que "não re-embedar o que não mudou".
|
|
234
|
+
|
|
235
|
+
| Objetivo | O que resolve |
|
|
236
|
+
|---|---|
|
|
237
|
+
| **Custo** (não pagar embedding do que não mudou) | O plano por hash acima |
|
|
238
|
+
| **Higiene** (não deixar chunk órfão de uma versão anterior do documento) | O `VectorStoreWriter` com `IncrementalIngestion` |
|
|
239
|
+
|
|
240
|
+
Os dois não competem; resolvem problemas diferentes. Adote o writer quando aceitar a dependência preview.
|
|
241
|
+
|
|
242
|
+
### Item aberto, medido em campo
|
|
243
|
+
|
|
244
|
+
**Threshold de similaridade e `k` por escopo ainda não têm regra.** Hoje o escopo institucional da base do GHLBrain roda **sem `LIMIT`** (`scan-ghlbrain.md:410`): a busca devolve tudo o que passa do threshold, e o custo do prompt varia com o tamanho da base. Definir `k` e o corte por escopo é trabalho pendente, não recomendação existente — registrado aqui para não ser reinventado como se fosse novo.
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
189
248
|
## Multi-tenant
|
|
190
249
|
|
|
191
250
|
Each tenant's knowledge is partitioned by `tenant_id`:
|
|
@@ -229,7 +288,11 @@ ALTER TABLE kb_embeddings ENABLE ROW LEVEL SECURITY;
|
|
|
229
288
|
- [ ] No `Microsoft.SemanticKernel` references in the project.
|
|
230
289
|
- [ ] Vector dimensions consistent between embedding model and `vector(N)` column definition.
|
|
231
290
|
- [ ] RLS enabled on `kb_embeddings` (or equivalent app-level guard documented in `decisions.md`).
|
|
232
|
-
- [ ]
|
|
291
|
+
- [ ] Ingestion follows §*Ingestão delta por lookup-key*: a pure `Plan(...)` produces `Added`/`Updated`/`Removed`/`Unchanged`, and `Unchanged` is never re-embedded.
|
|
292
|
+
- [ ] No `DELETE`-everything-then-reinsert: `Removed` is applied **after** `Added`/`Updated`, in the same transaction — there is no window where the search returns empty.
|
|
293
|
+
- [ ] `Updated` is an **upsert** on a deterministic id, never delete+insert.
|
|
294
|
+
- [ ] A duplicate lookup-key in the incoming set **fails** the ingestion, naming the key and both positions.
|
|
295
|
+
- [ ] Replanning the same input over the store it produced yields `IsNoOp == true` (idempotence, as a test).
|
|
233
296
|
|
|
234
297
|
---
|
|
235
298
|
|
|
@@ -240,7 +303,9 @@ ALTER TABLE kb_embeddings ENABLE ROW LEVEL SECURITY;
|
|
|
240
303
|
- `data-vector-search-rag-chunking` — chunk strategies per document type
|
|
241
304
|
- `infrastructure-neon-pgvector` — extension setup, `UseVector()`, HNSW parameter tuning
|
|
242
305
|
- `ai-agents-vector-data-extensions` — the official `Microsoft.Extensions.VectorData` abstraction, and when it's worth adopting instead of this custom implementation
|
|
306
|
+
- Reference implementation of the delta planner (compiles against the pin): `templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs` + `DeltaPlan.cs`
|
|
307
|
+
- `Microsoft.Extensions.DataIngestion` — https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dataingestion.vectorstorewriteroptions (preview; versão apurada 2026-09-08)
|
|
243
308
|
|
|
244
309
|
---
|
|
245
310
|
|
|
246
|
-
*MORPH-SPEC by Polymorphism Tech — ai-agents/rag-custom-pgvector.md
|
|
311
|
+
*MORPH-SPEC by Polymorphism Tech — ai-agents/rag-custom-pgvector.md v2.0 (2026-09-08)*
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
> **Keywords:** service tier, flex tier, cost optimization, async tier, priority tier
|
|
6
6
|
> **Read by Claude in:** implement
|
|
7
7
|
|
|
8
|
-
**Verified against:**
|
|
8
|
+
**Verified against:** OpenAI 2.13.0 + Microsoft.Extensions.AI 10.9.0 (ai-pin 2026-09-08). **Verificação documental** da política de tiers (platform.openai.com/docs/guides/service-tiers, lido 2026-09-08), sem cláusula `provado por`: o ai-kit **referencia** o pacote `OpenAI` no `.csproj` — contrato de versão, régua = restore (`NU1102`) — mas **não o exercita**; não existe um único `using OpenAI` em `src/` (medido 2026-09-08), logo um rename de API não reprova a PR. Ver a tabela "Dois níveis de garantia" no README do kit. **O nome e o tipo da propriedade C# foram medidos por reflexão sobre a assembly `OpenAI` 2.13.0 em 2026-09-08**, e o marcador `// VERIFY` desta página foi RESOLVIDO por essa medição. Last-verified: 2026-09-08.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -27,17 +27,23 @@ Use o service tier **flex** quando o agente roda em background, sem usuário agu
|
|
|
27
27
|
## A API
|
|
28
28
|
|
|
29
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"`.
|
|
30
|
+
> Para setar service tier, use o `ChatClient`/`ResponsesClient` direto (obtido do Model Registry ou da configuração).
|
|
36
31
|
>
|
|
37
|
-
>
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
32
|
+
> Isso foi **medido**, não suposto: `Microsoft.Extensions.AI.ChatOptions` 10.9.0 tem 20 propriedades e **nenhuma** delas é service tier (reflexão sobre `Microsoft.Extensions.AI.Abstractions` 10.9.0, 2026-09-08). O caminho por abstração é `ChatOptions.AdditionalProperties["service_tier"]` **combinado com** um `RawRepresentationFactory` que traduza o valor — sem essa tradução, a chave em `AdditionalProperties` não chega ao fio.
|
|
33
|
+
|
|
34
|
+
### O tipo é um struct, não uma string — e não existe `priority`
|
|
35
|
+
|
|
36
|
+
Medido na assembly `OpenAI` 2.13.0:
|
|
37
|
+
|
|
38
|
+
| Superfície | Propriedade | Tipo | Valores |
|
|
39
|
+
|---|---|---|---|
|
|
40
|
+
| Chat Completions | `ChatCompletionOptions.ServiceTier` | `ChatServiceTier?` | `Auto`, `Default`, `Flex`, `Scale` |
|
|
41
|
+
| Responses | `CreateResponseOptions.ServiceTier` | `ResponseServiceTier?` | `Auto`, `Default`, `Flex`, `Scale` |
|
|
42
|
+
|
|
43
|
+
Duas correções contra a versão anterior deste standard:
|
|
44
|
+
|
|
45
|
+
1. **`ServiceTier = "flex"` não compila.** O valor é `ChatServiceTier.Flex` (um struct de valores nomeados, no estilo dos "extensible enums" do SDK), não uma `string`.
|
|
46
|
+
2. **`priority` não existe no SDK 2.13.0.** Os quatro valores expostos são `Auto`, `Default`, `Flex` e `Scale`. Se a conta tem tier prioritário contratado, isso não aparece como membro tipado aqui — e este standard não vai fingir que aparece.
|
|
41
47
|
|
|
42
48
|
---
|
|
43
49
|
|
|
@@ -58,9 +64,7 @@ ChatClient chatClient = new(model, new ApiKeyCredential(apiKey));
|
|
|
58
64
|
|
|
59
65
|
ChatCompletionOptions flexOptions = new()
|
|
60
66
|
{
|
|
61
|
-
|
|
62
|
-
// Ver "Status de verificação da API .NET" acima.
|
|
63
|
-
ServiceTier = "flex",
|
|
67
|
+
ServiceTier = ChatServiceTier.Flex, // struct de valores nomeados, medido em OpenAI 2.13.0
|
|
64
68
|
};
|
|
65
69
|
|
|
66
70
|
ChatCompletion result = await chatClient.CompleteChatAsync(
|
|
@@ -94,7 +98,8 @@ string responseText = result.Content[0].Text;
|
|
|
94
98
|
|---------|--------------------------|
|
|
95
99
|
| Chat com usuário aguardando na tela | `default` (ou `auto`) |
|
|
96
100
|
| Job async — relatório, enriquecimento, briefing | `flex` |
|
|
97
|
-
| Job de alta prioridade com SLA apertado | `priority` (
|
|
101
|
+
| Job de alta prioridade com SLA apertado | `ChatServiceTier.Default` — **`priority` não existe** como valor tipado no SDK 2.13.0 (medido); um tier prioritário contratado com a OpenAI não tem membro correspondente aqui |
|
|
102
|
+
| Carga previsível e alta, com capacidade reservada | `ChatServiceTier.Scale` |
|
|
98
103
|
| Batch API (24 h) | Não se aplica — Batch tem custo próprio |
|
|
99
104
|
|
|
100
105
|
> `auto` (padrão da API): OpenAI decide o tier baseado na carga. Use `flex` explícito
|
|
@@ -107,7 +112,8 @@ string responseText = result.Content[0].Text;
|
|
|
107
112
|
| Anti-pattern | Problema |
|
|
108
113
|
|-------------|----------|
|
|
109
114
|
| Usar `flex` em completion interativa | Latência imprevisível — usuário percebe lentidão |
|
|
110
|
-
| Usar `
|
|
115
|
+
| Usar `Default` em batch noturno | Paga mais sem necessidade |
|
|
116
|
+
| Escrever `ServiceTier = "flex"` (string) | Não compila: o tipo é `ChatServiceTier` |
|
|
111
117
|
| Espalhar `ServiceTier = "flex"` por vários handlers | Usar middleware de ChatOptions para centralizar |
|
|
112
118
|
| Combinar flex tier com Batch API | São mecanismos distintos; não se somam |
|
|
113
119
|
|
|
@@ -116,7 +122,8 @@ string responseText = result.Content[0].Text;
|
|
|
116
122
|
## Checklist (verifiable by morph-eval)
|
|
117
123
|
|
|
118
124
|
- [ ] Tier flex usado somente em jobs assíncronos (Worker Service / Hangfire), nunca em handlers de request HTTP síncrono
|
|
119
|
-
- [ ] `ServiceTier`
|
|
125
|
+
- [ ] `ServiceTier` usa o valor tipado (`ChatServiceTier.Flex` / `ResponseServiceTier.Flex`), nunca uma string
|
|
126
|
+
- [ ] Nenhuma referência a um tier `priority` (não existe no SDK 2.13.0)
|
|
120
127
|
- [ ] Jobs com flex tier não têm SLA de latência definido no contrato com o usuário final
|
|
121
128
|
- [ ] Se o agente usa `IChatClient` abstrato, o `ServiceTier` foi validado que é passado corretamente
|
|
122
129
|
|
|
@@ -128,8 +135,9 @@ string responseText = result.Content[0].Text;
|
|
|
128
135
|
- `ai-agents-batching` — alternativa de custo para volume alto de prompts independentes
|
|
129
136
|
- `ai-agents-middleware-patterns` (Onda 2) — middleware para injetar `ChatOptions` globalmente
|
|
130
137
|
- `ai-agents-providers-model-registry` — configuração provider-agnostic
|
|
131
|
-
- OpenAI Service Tiers: https://platform.openai.com/docs/guides/service-tiers
|
|
138
|
+
- OpenAI Service Tiers: https://platform.openai.com/docs/guides/service-tiers (lido 2026-09-08)
|
|
139
|
+
- Superfície C# medida na assembly `OpenAI` 2.13.0 em 2026-09-08
|
|
132
140
|
|
|
133
141
|
---
|
|
134
142
|
|
|
135
|
-
*MORPH-SPEC by Polymorphism Tech — ai-agents/service-tier-flex.md
|
|
143
|
+
*MORPH-SPEC by Polymorphism Tech — ai-agents/service-tier-flex.md v2.0 (2026-09-08)*
|