@polymorphism-tech/morph-spec 8.34.2 → 8.35.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.
Files changed (325) hide show
  1. package/CLAUDE.md +20 -3
  2. package/README.md +2 -2
  3. package/bin/morph-spec.js +18 -4
  4. package/bin/validate.js +379 -379
  5. package/claude-plugin.json +1 -1
  6. package/docs/CHEATSHEET.md +5 -4
  7. package/docs/QUICKSTART.md +1 -1
  8. package/framework/MORPH.md +16 -17
  9. package/framework/agents.json +197 -44
  10. package/framework/ai-pin.json +22 -0
  11. package/framework/commands/morph-media.md +45 -0
  12. package/framework/docs/CLI.md +234 -9
  13. package/framework/evals/proof-rubrics/README.md +76 -0
  14. package/framework/evals/proof-rubrics/eval-de-modelo.md +64 -0
  15. package/framework/evals/proof-rubrics/fiacao.md +54 -0
  16. package/framework/evals/proof-rubrics/guard-cego.md +52 -0
  17. package/framework/evals/proof-rubrics/media-claims.md +109 -0
  18. package/framework/evals/proof-rubrics/mutation-proof.md +77 -0
  19. package/framework/evals/proof-rubrics/observabilidade-genai.md +119 -0
  20. package/framework/evals/proof-rubrics/verde-nao-e-coberto.md +48 -0
  21. package/framework/evals/rubrics/architecture.md +30 -0
  22. package/framework/evals/rubrics/code-quality.md +26 -0
  23. package/framework/evals/rubrics/test-coverage.md +20 -0
  24. package/framework/hooks/claude-code/core/protect-spec-files.js +41 -4
  25. package/framework/hooks/claude-code/statusline.sh +11 -11
  26. package/framework/hooks/git/commit-msg/conventional-commits.sh +33 -33
  27. package/framework/hooks/git/pre-commit/agents.sh +25 -25
  28. package/framework/hooks/git/pre-commit/orchestrator.sh +64 -64
  29. package/framework/hooks/git/pre-commit/specs.sh +50 -50
  30. package/framework/hooks/git/pre-push/run-tests.sh +44 -44
  31. package/framework/hooks/shared/e2e-check.js +135 -22
  32. package/framework/hooks/shared/stdin-reader.js +26 -26
  33. package/framework/rules/ai-agents-standards.md +14 -2
  34. package/framework/schemas/ai-pin.schema.json +97 -0
  35. package/framework/schemas/config.schema.json +107 -0
  36. package/framework/schemas/feature.schema.json +23 -4
  37. package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
  38. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
  39. package/framework/skills/core/morph-apply/SKILL.md +26 -5
  40. package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
  41. package/framework/skills/core/morph-eval/SKILL.md +1 -1
  42. package/framework/skills/core/morph-hotfix/SKILL.md +2 -2
  43. package/framework/skills/core/morph-implement/SKILL.md +18 -2
  44. package/framework/skills/core/morph-media/SKILL.md +215 -0
  45. package/framework/skills/core/morph-plan/SKILL.md +33 -2
  46. package/framework/skills/core/morph-proposal/SKILL.md +1 -1
  47. package/framework/skills/core/morph-review/SKILL.md +166 -9
  48. package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
  49. package/framework/skills/core/morph-standards/SKILL.md +1 -1
  50. package/framework/skills/core/morph-uiux/SKILL.md +1 -1
  51. package/framework/standards/PROVENANCE.json +81 -3
  52. package/framework/standards/STANDARDS.json +1483 -839
  53. package/framework/standards/ai-agents/agent-archetypes.md +160 -0
  54. package/framework/standards/ai-agents/agent-session.md +164 -68
  55. package/framework/standards/ai-agents/agent-spec.md +196 -0
  56. package/framework/standards/ai-agents/batching.md +61 -37
  57. package/framework/standards/ai-agents/context-providers.md +97 -24
  58. package/framework/standards/ai-agents/conversational-agent-with-phases.md +239 -0
  59. package/framework/standards/ai-agents/cost-and-budget.md +256 -0
  60. package/framework/standards/ai-agents/durable-workflows-hitl.md +98 -5
  61. package/framework/standards/ai-agents/evals-with-cache.md +289 -0
  62. package/framework/standards/ai-agents/guardrails.md +222 -0
  63. package/framework/standards/ai-agents/llm-runtime-defaults.md +226 -0
  64. package/framework/standards/ai-agents/mcp-server.md +119 -18
  65. package/framework/standards/ai-agents/mcp-tools.md +85 -32
  66. package/framework/standards/ai-agents/media-pipeline.md +352 -0
  67. package/framework/standards/ai-agents/media-video.md +267 -0
  68. package/framework/standards/ai-agents/middleware-patterns.md +39 -5
  69. package/framework/standards/ai-agents/modalities-image-gen.md +354 -105
  70. package/framework/standards/ai-agents/modalities-speech-to-text.md +8 -2
  71. package/framework/standards/ai-agents/modalities-text-to-speech.md +10 -2
  72. package/framework/standards/ai-agents/modalities-vision.md +6 -2
  73. package/framework/standards/ai-agents/multi-agent-patterns.md +61 -5
  74. package/framework/standards/ai-agents/observability-patterns.md +227 -17
  75. package/framework/standards/ai-agents/production.md +38 -9
  76. package/framework/standards/ai-agents/prompt-sources.md +389 -0
  77. package/framework/standards/ai-agents/providers/model-registry.md +174 -39
  78. package/framework/standards/ai-agents/rag-custom-pgvector.md +69 -4
  79. package/framework/standards/ai-agents/service-tier-flex.md +27 -19
  80. package/framework/standards/ai-agents/setup.md +166 -50
  81. package/framework/standards/ai-agents/structured-output.md +34 -3
  82. package/framework/standards/ai-agents/sweet-spot.md +23 -3
  83. package/framework/standards/ai-agents/testing-ai.md +236 -0
  84. package/framework/standards/ai-agents/vector-data-extensions.md +50 -20
  85. package/framework/standards/ai-agents/workflows.md +27 -7
  86. package/framework/standards/frontend/design-system/ai-image-generation.md +12 -0
  87. package/framework/standards/frontend/design-system/ai-video-generation.md +13 -0
  88. package/framework/standards/infrastructure/docker/local-compose-isolation.md +3 -1
  89. package/framework/templates/.idea/morph-templates.xml +92 -0
  90. package/framework/templates/.vscode/morph-templates.code-snippets +186 -0
  91. package/framework/templates/IDE-SNIPPETS.md +262 -262
  92. package/framework/templates/REGISTRY.json +13 -0
  93. package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
  94. package/framework/templates/code/dotnet/ai-agents/AgentBootstrap.cs.template +39 -39
  95. package/framework/templates/code/dotnet/ai-agents/EmbeddingService.cs.template +68 -68
  96. package/framework/templates/code/dotnet/ai-agents/ModelRegistry.cs.template +117 -117
  97. package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +1 -1
  98. package/framework/templates/code/dotnet/ai-agents/ResilientToolMiddleware.cs.template +61 -61
  99. package/framework/templates/code/dotnet/ai-agents/VectorSearchTool.cs.template +107 -107
  100. package/framework/templates/code/dotnet/ai-agents/model-registry.json.template +58 -58
  101. package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +281 -281
  102. package/framework/templates/code/dotnet/database/migration.cs +83 -83
  103. package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +21 -21
  104. package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -4
  105. package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -4
  106. package/framework/templates/code/dotnet/feature/validator.cs.hbs +15 -15
  107. package/framework/templates/code/sql/ai-agents/agent-prompts-migration.sql.template +1 -1
  108. package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -91
  109. package/framework/templates/code/typescript/contracts.ts +167 -167
  110. package/framework/templates/docs/clarifications.md +253 -253
  111. package/framework/templates/docs/schema-analysis.md +119 -119
  112. package/framework/templates/docs/ui-components.md +52 -52
  113. package/framework/templates/docs/ui-design-system.md +76 -76
  114. package/framework/templates/docs/ui-flows.md +167 -167
  115. package/framework/templates/docs/ui-mockups.md +98 -98
  116. package/framework/templates/dotnet/ai-kit/Directory.Build.props +25 -0
  117. package/framework/templates/dotnet/ai-kit/Directory.Packages.props +26 -0
  118. package/framework/templates/dotnet/ai-kit/Morph.AiKit.sln +56 -0
  119. package/framework/templates/dotnet/ai-kit/NuGet.config +12 -0
  120. package/framework/templates/dotnet/ai-kit/README.md +128 -0
  121. package/framework/templates/dotnet/ai-kit/global.json +9 -0
  122. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentApi.cs +65 -0
  123. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactory.cs +289 -0
  124. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactoryOptions.cs +91 -0
  125. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpec.cs +91 -0
  126. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpecOptions.cs +181 -0
  127. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/AiKitAssemblyMarker.cs +14 -0
  128. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/ConversationStore.cs +174 -0
  129. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/IConversationStore.cs +54 -0
  130. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/InMemoryConversationStore.cs +75 -0
  131. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/CountingChatClient.cs +71 -0
  132. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalAssertion.cs +246 -0
  133. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheMissException.cs +57 -0
  134. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheOptions.cs +78 -0
  135. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheStamp.cs +225 -0
  136. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalFixture.cs +463 -0
  137. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalMode.cs +32 -0
  138. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalQualityEvaluators.cs +49 -0
  139. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalScenario.cs +214 -0
  140. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalSummary.cs +168 -0
  141. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/OfflineChatClient.cs +142 -0
  142. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/ShortPathResponseCache.cs +349 -0
  143. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaGenerator.cs +42 -0
  144. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaProvider.cs +77 -0
  145. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaArtifact.cs +28 -0
  146. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaDisclosure.cs +107 -0
  147. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaGenerator.cs +253 -0
  148. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaIdempotencyKey.cs +103 -0
  149. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJob.cs +259 -0
  150. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobId.cs +21 -0
  151. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobState.cs +47 -0
  152. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaPricing.cs +102 -0
  153. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaProvenance.cs +44 -0
  154. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaRequest.cs +192 -0
  155. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaResult.cs +94 -0
  156. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaReview.cs +99 -0
  157. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaSeams.cs +97 -0
  158. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaStore.cs +133 -0
  159. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MorphMedia.cs +93 -0
  160. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/GoogleImageProvider.cs +112 -0
  161. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/OpenAIImageProvider.cs +288 -0
  162. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/VeoVideoProvider.cs +158 -0
  163. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/IUsageCostSink.cs +29 -0
  164. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostMiddleware.cs +208 -0
  165. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostRecord.cs +95 -0
  166. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Morph.AiKit.csproj +38 -0
  167. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphOpenTelemetryExtensions.cs +119 -0
  168. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphTelemetryOptions.cs +82 -0
  169. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/IProviderClientFactory.cs +33 -0
  170. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelAlias.cs +267 -0
  171. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelRegistry.cs +474 -0
  172. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/model-registry.v2.json +87 -0
  173. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs +169 -0
  174. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaPlan.cs +49 -0
  175. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentFactoryTests.cs +495 -0
  176. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentSpecTests.cs +260 -0
  177. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ConversationStoreTests.cs +405 -0
  178. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/DeltaIngestTests.cs +379 -0
  179. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalAssertionTests.cs +197 -0
  180. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheMissTests.cs +139 -0
  181. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheStampTests.cs +157 -0
  182. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFailuresTests.cs +178 -0
  183. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFixtureTests.cs +153 -0
  184. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalRefreshTests.cs +194 -0
  185. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalWorkspace.cs +86 -0
  186. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/KitEvals.cs +213 -0
  187. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/OfflineChatClientTests.cs +95 -0
  188. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClient.cs +225 -0
  189. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClientTests.cs +215 -0
  190. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeClock.cs +33 -0
  191. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeMediaProvider.cs +89 -0
  192. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeProviderClientFactory.cs +55 -0
  193. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeUsageCostSink.cs +60 -0
  194. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/InMemoryMediaStore.cs +131 -0
  195. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAccessibilityTests.cs +133 -0
  196. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAliasIsNotAnAgentTests.cs +127 -0
  197. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +216 -0
  198. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaGeneratorTests.cs +264 -0
  199. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaIdempotencyKeyTests.cs +148 -0
  200. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaJobStateTests.cs +184 -0
  201. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaReviewTests.cs +89 -0
  202. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaStoreTests.cs +98 -0
  203. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ModelRegistryTests.cs +451 -0
  204. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Morph.AiKit.Tests.csproj +76 -0
  205. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/SkeletonSmokeTests.cs +33 -0
  206. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/TelemetryTests.cs +261 -0
  207. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/UsageCostMiddlewareTests.cs +374 -0
  208. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/.morph-eval-cache.json +12 -0
  209. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/contents.data +13 -0
  210. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/entry.json +7 -0
  211. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/contents.data +13 -0
  212. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/entry.json +7 -0
  213. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/contents.data +13 -0
  214. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/entry.json +7 -0
  215. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/contents.data +13 -0
  216. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/entry.json +7 -0
  217. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/orcamento/acme/a-resposta-estruturada.json +24 -0
  218. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/a-saudacao.json +23 -0
  219. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/b-escalonamento.json +24 -0
  220. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/globex/a-saudacao.json +23 -0
  221. package/framework/templates/feature/decisions.md +122 -122
  222. package/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +43 -43
  223. package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
  224. package/framework/templates/frontend/nextjs/env.mjs.hbs +32 -32
  225. package/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -56
  226. package/framework/templates/frontend/nextjs/page.tsx.hbs +22 -22
  227. package/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -26
  228. package/framework/templates/frontend/nextjs/use-feature.ts.hbs +54 -54
  229. package/framework/templates/infrastructure/docker/Dockerfile.template +58 -58
  230. package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
  231. package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
  232. package/framework/templates/infrastructure/github/README.md +56 -56
  233. package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -45
  234. package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -27
  235. package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -59
  236. package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -39
  237. package/framework/templates/integrations/asaas-client.cs +387 -387
  238. package/framework/templates/integrations/asaas-webhook.cs +351 -351
  239. package/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -76
  240. package/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -100
  241. package/framework/templates/meta-prompts/validators/pre-commit-validator.md +95 -95
  242. package/framework/templates/project/validate.js +120 -120
  243. package/framework/templates/state.template.json +17 -17
  244. package/framework/templates/ui/design-system.css +226 -226
  245. package/package.json +3 -3
  246. package/src/commands/dashboard/dashboard.js +53 -53
  247. package/src/commands/e2e/e2e.js +15 -2
  248. package/src/commands/index.js +13 -13
  249. package/src/commands/project/checkpoint.js +209 -209
  250. package/src/commands/project/doctor.js +140 -5
  251. package/src/commands/project/update.js +469 -153
  252. package/src/commands/project/worktree.js +8 -1
  253. package/src/commands/state/advance.js +24 -2
  254. package/src/commands/state/approve.js +33 -1
  255. package/src/commands/state/create.js +72 -11
  256. package/src/commands/state/finish.js +333 -21
  257. package/src/commands/state/gate-check.js +190 -6
  258. package/src/commands/state/score.js +36 -1
  259. package/src/commands/validation/verify.js +134 -25
  260. package/src/core/state/phase-state-machine.js +197 -197
  261. package/src/core/state/state-manager.js +9 -1
  262. package/src/core/templates/template-renderer.js +477 -477
  263. package/src/dashboard/app/components/DetailPanel.jsx +11 -11
  264. package/src/dashboard/app/components/FlowGraph.jsx +17 -17
  265. package/src/dashboard/app/components/SearchFilter.jsx +22 -22
  266. package/src/dashboard/app/hooks/useDetailPanel.js +15 -15
  267. package/src/dashboard/app/main.jsx +13 -13
  268. package/src/dashboard/app/pages/AgentMap.jsx +370 -370
  269. package/src/dashboard/app/pages/PhasePipeline.jsx +408 -408
  270. package/src/dashboard/app/pages/RulesMap.jsx +273 -273
  271. package/src/dashboard/app/pages/SkillsLibrary.jsx +366 -366
  272. package/src/dashboard/app/pages/Standards.jsx +332 -332
  273. package/src/dashboard/app/styles/index.css +47 -47
  274. package/src/dashboard/index.html +12 -12
  275. package/src/dashboard/package.json +24 -24
  276. package/src/dashboard/scanner/phases-scanner.js +15 -15
  277. package/src/dashboard/scanner/rubrics-scanner.js +12 -12
  278. package/src/dashboard/scanner/rules-scanner.js +37 -37
  279. package/src/dashboard/scanner/skills-scanner.js +43 -43
  280. package/src/dashboard/scanner/squads-scanner.js +13 -13
  281. package/src/dashboard/vite-plugin-morph-data.js +17 -17
  282. package/src/dashboard/vite.config.js +24 -24
  283. package/src/lib/ai/ai-checks.js +182 -0
  284. package/src/lib/ai/ai-project-scan.js +347 -0
  285. package/src/lib/ai/code-audit.js +181 -0
  286. package/src/lib/ai/comment-stripper.js +184 -0
  287. package/src/lib/ai/pin-drift.js +138 -0
  288. package/src/lib/ai/registry-audit.js +285 -0
  289. package/src/lib/detectors/design-system-detector.js +188 -188
  290. package/src/lib/detectors/index.js +217 -217
  291. package/src/lib/e2e/compose-env.js +50 -4
  292. package/src/lib/evaluator-report.js +269 -15
  293. package/src/lib/generators/design-system-generator.js +508 -508
  294. package/src/lib/generators/settings-generator.js +209 -209
  295. package/src/lib/git/default-branch.js +92 -4
  296. package/src/lib/hooks/hook-executor.js +167 -167
  297. package/src/lib/installers/effects.js +193 -0
  298. package/src/lib/installers/mcp-installer.js +719 -719
  299. package/src/lib/installers/templates-reconcile.js +3 -3
  300. package/src/lib/risk-detector.js +284 -0
  301. package/src/lib/standards/verified-against.js +276 -0
  302. package/src/lib/tasks/eval-node.js +485 -0
  303. package/src/lib/tasks/linux-runner.js +297 -0
  304. package/src/lib/tasks/task-classifier.js +30 -30
  305. package/src/lib/tasks/task-parser.js +209 -209
  306. package/src/lib/tasks/test-nodes.js +486 -0
  307. package/src/lib/tasks/test-runner.js +410 -33
  308. package/src/lib/validators/checkpoint-persistence.js +39 -39
  309. package/src/lib/validators/css/css-validator.js +340 -340
  310. package/src/lib/validators/shared/emit-validator-dispatch.js +14 -14
  311. package/src/lib/validators/shared/issue-counter.js +14 -14
  312. package/src/lib/validators/verify-runner.js +583 -28
  313. package/src/lib/worktree/docker-audit.js +287 -0
  314. package/src/lib/worktree/env-allocator.js +24 -0
  315. package/src/lib/worktree/worktree-audit.js +30 -1
  316. package/src/scripts/setup-infra.js +24 -11
  317. package/src/utils/agent-id-mapper.js +11 -11
  318. package/src/utils/agents-installer.js +18 -8
  319. package/src/utils/claude-md-injector.js +10 -5
  320. package/src/utils/claude-settings-manager.js +300 -300
  321. package/src/utils/file-copier.js +11 -4
  322. package/src/utils/hooks-installer.js +29 -26
  323. package/src/utils/skills-installer.js +36 -29
  324. package/src/utils/version-checker.js +68 -3
  325. package/framework/standards/ai-agents/prompts-in-db.md +0 -214
@@ -0,0 +1,160 @@
1
+ # Agent Archetypes — as quatro formas de agente, e como escolher uma
2
+
3
+ > **Scope:** stacks=["dotnet"]
4
+ > **Layer:** 1 (on-keyword)
5
+ > **Keywords:** agent archetype, arquetipo de agente, qual forma de agente, conversational agent, one-shot agent, batch agent, vision agent, chat with history
6
+ > **Read by Claude in:** plan (escolher a forma do agente antes de quebrar a feature em tasks)
7
+
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/Agents/AgentFactory.cs` e `.../Conversation/ConversationStore.cs` (arquétipos **one-shot em batch** e **chat com histórico** — o conversacional com fases NÃO tem lastro no kit, e `ai-agents-conversational-agent-with-phases` declara isso no próprio cabeçalho). O arquétipo visão + structured output é **verificação documental** — o ai-kit não exercita multimodalidade. Last-verified: 2026-09-08.
9
+
10
+ ---
11
+
12
+ ## Como escolher
13
+
14
+ `ai-agents-sweet-spot` decide **se** o caso pede um agente ou um workflow. Este standard entra
15
+ depois, e decide **qual forma** o agente tem. A escolha é de **fase de plano**: ela muda o desenho
16
+ das tasks, não uma linha de implementação.
17
+
18
+ Três perguntas, nesta ordem — a primeira que responder "sim" fecha a escolha:
19
+
20
+ | # | Pergunta | Se sim |
21
+ |---|---|---|
22
+ | 1 | O agente atende **um interlocutor ao longo do tempo**, e o que ele pode fazer muda conforme o ponto da conversa? | **Conversacional com fases** — e leia `ai-agents-conversational-agent-with-phases` |
23
+ | 2 | O agente é chamado por um **job**, produz um artefato e morre? | **One-shot em batch** |
24
+ | 3 | A entrada é **imagem ou PDF** e a saída precisa ser um objeto tipado? | **Visão com structured output** |
25
+
26
+ Se a resposta a (1) for sim, a **propriedade do histórico** ainda é uma decisão separada — é o
27
+ quarto arquétipo, e ele não é alternativo ao primeiro (ver `## Lastro de campo por arquétipo`).
28
+
29
+ **Regra que atravessa os quatro:** o agente referencia **alias**, nunca id de modelo
30
+ (`ai-agents-providers-model-registry`), e a forma escolhida não muda isso.
31
+
32
+ ---
33
+
34
+ ## Conversacional com fases
35
+
36
+ Agente **único** que atende uma conversa inteira. As quatro propriedades que definem a forma:
37
+
38
+ - **Fase derivada por turno**, de estado observável, nunca de memória do modelo.
39
+ - **Allow-list de tools por fase** — o agente na fase de triagem não enxerga a tool de fechamento.
40
+ - **Teto de tool calls por turno**, com uma tool isenta quando existe uma ação que sempre pode
41
+ acontecer.
42
+ - **Dono do próprio histórico** — o agente decide o que entra no contexto do turno.
43
+
44
+ Multiplicar agentes por fase é o erro clássico aqui: cada fase vira um agente, e a transição entre
45
+ fases vira orquestração que ninguém pediu. A fase é **dado do turno**, não identidade de agente.
46
+
47
+ O aprofundamento — compositor de turno determinístico, os dois estágios da allow-list, `RequireAny`
48
+ e o teto — está em `ai-agents-conversational-agent-with-phases`, que declara fonte única.
49
+
50
+ ---
51
+
52
+ ## One-shot em batch
53
+
54
+ Agente **recriado por invocação**. Prompt e alias entram como **parâmetro de método**, nunca como
55
+ estado do objeto; o agente não sobrevive à chamada.
56
+
57
+ - Sempre dentro de um **job assíncrono**, nunca no caminho de uma requisição HTTP síncrona.
58
+ - Saída tipada com `RunAsync<T>` — quem chama um agente de batch quer um objeto, não um parágrafo.
59
+ - Construir agente é barato: recrie por invocação em vez de guardar um vivo e mutá-lo.
60
+
61
+ O ai-kit compila exatamente essa forma: `AgentFactory.Create(AgentSpec)` recebe **a spec inteira
62
+ como argumento** e devolve um `AIAgent` novo, sem estado compartilhado entre chamadas.
63
+
64
+ ---
65
+
66
+ ## Visão com structured output
67
+
68
+ Entrada multimodal (`DataContent`/`UriContent`) + saída tipada na **mesma** chamada. PDF é
69
+ rasterizado e vai **uma chamada por página** — não existe "mandar o PDF inteiro" que não seja isso
70
+ por baixo.
71
+
72
+ > **Este arquétipo tem ZERO exemplares no acervo.** Ele é forma **projetada**, não destilada. Os
73
+ > dois standards que o sustentam existem separadamente (`ai-agents-modalities-vision` e
74
+ > `ai-agents-structured-output`); o que não existe é um caso de campo que combine os dois numa
75
+ > chamada só. Quem for o primeiro a implementá-lo deve tratar as afirmações desta seção como
76
+ > hipótese a verificar, e voltar aqui com a medição.
77
+
78
+ Os anti-padrões que o acervo **já cometeu** — duas meias-formas e uma implementação quebrada:
79
+
80
+ | Meia-forma medida | O que faltou |
81
+ |---|---|
82
+ | Visão **sem** structured — a resposta volta em prosa e alguém a interpreta depois | O parser vira dívida invisível: o formato da prosa é contrato não declarado |
83
+ | Structured **sem** visão — o objeto é tipado, mas a imagem foi descrita antes por outra chamada | Duas chamadas pagas onde uma bastava, e o erro de descrição não é mais rastreável até a origem |
84
+ | Foto entregue como **URL dentro do texto** do prompt, JSON pedido em prosa, e a resposta limpa com strip de code fence | Isto não é o arquétipo: é o que se faz quando ele não é conhecido. `DataContent`/`UriContent` existem para isso, e `ChatResponseFormatJson` para o outro lado |
85
+
86
+ ---
87
+
88
+ ## Chat com histórico
89
+
90
+ A **conversa** é a fonte de verdade, e a projeção papel → `ChatMessage` acontece **num lugar só**.
91
+
92
+ - Carregar e anexar histórico é responsabilidade de um tipo dedicado, não do handler.
93
+ - A projeção (quem é `user`, quem é `assistant`, o que vira `system`) é uma função pura, testável
94
+ sem banco.
95
+ - Duas projeções em dois arquivos é como um histórico começa a divergir de si mesmo.
96
+
97
+ O ai-kit compila esta forma em `ConversationStore` (um `ChatHistoryProvider` sobre a interface
98
+ mínima `IConversationStore` — `LoadAsync`/`AppendAsync`, sem tipo de banco na assinatura).
99
+
100
+ ---
101
+
102
+ ## Lastro de campo por arquétipo
103
+
104
+ Esta seção existe porque um catálogo que finge quatro instâncias iguais envelhece mal. O lastro é
105
+ desigual, e saber **onde** ele é fino é parte da informação:
106
+
107
+ | Arquétipo | Exemplares no acervo | Observação |
108
+ |---|---|---|
109
+ | Conversacional com fases | **1**, em produção | Fonte única; o standard dedicado declara isso no próprio corpo |
110
+ | One-shot em batch | **3** | O mais lastreado dos quatro, e por isso o de menor risco |
111
+ | Visão com structured output | **0** | Forma projetada. Existem duas meias-formas, e uma implementação quebrada |
112
+ | Chat com histórico | **1** | E é **o mesmo agente** do primeiro arquétipo |
113
+
114
+ **Consequência de forma, e é a razão desta tabela:** o primeiro e o quarto arquétipos **não são
115
+ independentes**. São dois eixos do mesmo agente — *fases* (o que ele pode fazer agora) × *propriedade
116
+ do histórico* (quem decide o que ele lembra). Um agente conversacional que delega o histórico a um
117
+ framework externo continua sendo o primeiro arquétipo, e perdeu o quarto. Escolher "conversacional"
118
+ não escolhe o histórico; escolher "chat com histórico" não escolhe as fases.
119
+
120
+ ---
121
+
122
+ ## Anti-patterns
123
+
124
+ | Anti-pattern | Por quê é problema | Solução |
125
+ |---|---|---|
126
+ | Um agente por fase da conversa | A transição entre fases vira orquestração que ninguém pediu, e o histórico se fragmenta | Um agente, fase como dado do turno |
127
+ | Agente one-shot guardado como singleton e mutado entre chamadas | Estado vaza entre invocações independentes; um prompt de uma execução aparece na seguinte | Recrie por invocação — a construção é barata |
128
+ | Agente de batch no caminho síncrono de uma requisição | Latência de LLM no p99 do endpoint, sem retry e sem visibilidade | Job assíncrono |
129
+ | Imagem descrita numa chamada e tipada noutra | Duas chamadas pagas, e o erro de descrição deixa de ser rastreável | Uma chamada multimodal com `RunAsync<T>` |
130
+ | Projeção papel → `ChatMessage` em dois arquivos | Os dois divergem, e o bug aparece como "o agente esqueceu" | Uma projeção, pura e testável |
131
+ | Escolher o arquétipo na implementação | A forma muda o desenho das tasks; escolhida depois, ela vira refactor | Escolha na fase de plano, e registre em `decisions.md` |
132
+
133
+ ---
134
+
135
+ ## Checklist (verifiable by morph-eval)
136
+
137
+ - [ ] O arquétipo escolhido está **nomeado** no `decisions.md` da feature, com a pergunta de
138
+ `## Como escolher` que o decidiu
139
+ - [ ] Nenhum agente novo por fase de conversa — a fase é dado do turno
140
+ - [ ] Agente one-shot recebe prompt e alias como parâmetro, e não guarda estado entre invocações
141
+ - [ ] Agente de batch roda em job assíncrono
142
+ - [ ] Se há multimodalidade com saída tipada: uma única chamada, com `DataContent`/`UriContent`
143
+ - [ ] A projeção papel → `ChatMessage` existe em exatamente um lugar
144
+ - [ ] O agente referencia alias do registry, nunca id de modelo
145
+
146
+ ---
147
+
148
+ ## References
149
+
150
+ - `ai-agents-sweet-spot` — decide **se** é agente ou workflow; este standard só entra depois
151
+ - `ai-agents-conversational-agent-with-phases` — o aprofundamento do primeiro arquétipo
152
+ - `ai-agents-agent-spec` — a forma do agente **como dado**, comum aos quatro
153
+ - `ai-agents-providers-model-registry` — alias, e por que o modelo não aparece na spec
154
+ - `ai-agents-structured-output` — `RunAsync<T>` e o schema da saída
155
+ - `ai-agents-modalities-vision` — a metade multimodal do terceiro arquétipo
156
+ - `ai-agents-agent-session` — histórico e reducers, quando o quarto arquétipo cresce
157
+
158
+ ---
159
+
160
+ *MORPH-SPEC by Polymorphism Tech — ai-agents/agent-archetypes.md v1.0 (2026-09-08)*
@@ -1,51 +1,139 @@
1
- # Agent Session — Conversation state and chat reducers
1
+ # Agent Session — de onde vem o histórico de conversa
2
2
 
3
3
  > **Scope:** stacks=["dotnet"]
4
4
  > **Layer:** 2 (on-keyword)
5
- > **Keywords:** agent session, chat history, conversation state, chat reducer, history truncation, AgentThread
5
+ > **Keywords:** agent session, chat history, conversation state, chat reducer, history truncation, ChatHistoryProvider, conversa própria, multi-tenant
6
6
  > **Read by Claude in:** implement
7
7
 
8
- **Verified against:** MAF 1.0 GA. Last-verified: 2026-05-19.
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/Conversation/ConversationStore.cs` (a subclasse de `ChatHistoryProvider`, a invariante de instância única e o teste de duas sessões concorrentes). Nomes de tipo e membros medidos por reflexão sobre `Microsoft.Agents.AI.Abstractions` 1.20.0 em 2026-09-08. Last-verified: 2026-09-08.
9
9
 
10
10
  ---
11
11
 
12
- ## Quando usar AgentSession
12
+ ## O critério — de onde o histórico deve vir
13
13
 
14
- Use `AgentSession` quando o agente é **conversacional** — há uma UI de chat que mantém histórico entre turnos do usuário.
14
+ **Primeiro o critério, depois o veredito.** Existem três fontes possíveis de histórico e elas não são intercambiáveis:
15
15
 
16
- **Use AgentSession quando:**
17
- - Existe uma interface de chat (web, mobile, CLI interativo)
18
- - O agente precisa lembrar o que foi dito nos turnos anteriores da mesma conversa
19
- - Há perguntas de follow-up ("e agora?", "altere o segundo ponto", "lembra do que disse sobre X?")
16
+ | Situação | Fonte de histórico |
17
+ |---|---|
18
+ | A conversa carrega **campos de negócio** além das mensagens (usage por turno, título, dossiê, takeover humano, estado de funil) | **Conversa própria** — tabela/`jsonb` do projeto, exposta por um `ChatHistoryProvider` seu |
19
+ | O histórico precisa ser **visível e manipulável pela aplicação** (retry, remontagem, auditoria, edição, exclusão a pedido do titular) | **Conversa própria** |
20
+ | Multi-tenant com isolamento por chave composta e retenção sob controle do projeto | **Conversa própria** |
21
+ | O histórico é **só** a lista de mensagens, sem campo próprio, e o projeto não precisa lê-lo fora do agente | `AgentSession` + um `ChatHistoryProvider` embutido |
22
+ | Protótipo, CLI, demo, teste | `InMemoryChatHistoryProvider` |
20
23
 
21
- **NÃO use AgentSession quando:**
22
- - O agente é one-shot (gerador, executor, classificador) — recebe uma entrada, devolve uma saída, fim
23
- - Agentes stateless em pipeline multi-agent — cada chamada é independente
24
- - Jobs de batch/background — não há conversa; histórico não faz sentido
24
+ **O veredito da casa: conversa própria como default.** Isso não é preferência — é a aplicação do critério acima aos projetos que existem. GHLBrain, MORPH_OS e ProspectPRO caem todos nas três primeiras linhas.
25
25
 
26
- > "Add Memory/Session because agents need state" é um anti-pattern de `sweet-spot.md`.
27
- > Só adicione quando uma UI de chat real existe.
26
+ ### Os três fundamentos, cada um citável
27
+
28
+ 1. **ADR D3 do GHLBrain.** O estado da conversa vive em `conv_checkpoints`; `ToolAgentRunner.cs:126-130` roda *"sem AgentThread/sessão"* — porque o **retry depende de o histórico ser visível e manipulável**: para repetir uma volta que falhou é preciso remontar as mensagens, e não dá para remontar o que está dentro de um objeto opaco. Registrado em `docs/specs/elevacao-9/brutos/scan-ghlbrain.md:58` e `:599`.
29
+ 2. **Doc oficial de self-hosting** (learn.microsoft.com/en-us/agent-framework/hosting/self-hosting/, `ms.date` 2026-08-17), verbatim: *"MAF doesn't include a general-purpose durable session store"*. Produção exige implementação própria. A mesma página recomenda, em conversa longa, um `ChatHistoryProvider` externo **com mensagens por linha** em vez de reescrever a sessão inteira a cada turno.
30
+ 3. **Padrão do canal** (Rasmus, parte 06 — "Conversations"): objeto de conversa próprio do domínio, com **um** mapper para `ChatMessage`. A conversa é entidade de negócio; o formato do provedor é detalhe de transporte.
31
+
32
+ ### Ligação com a Responses API
33
+
34
+ Com `store: true` (o default da Responses API) **o histórico foge para o provedor** e passa a existir em dois lugares. Quem usa conversa própria mantém **`store: false`** — ver `ai-agents-setup` §*`store: false` é a regra da casa*, incluindo o atalho `AsIChatClientWithStoredOutputDisabled`.
35
+
36
+ ### Quando NÃO há histórico nenhum
37
+
38
+ - Agente one-shot (gerador, executor, classificador) — recebe uma entrada, devolve uma saída, fim.
39
+ - Agentes stateless em pipeline multi-agent — cada chamada é independente.
40
+ - Jobs de batch/background — não há conversa.
41
+
42
+ > *"Add Memory/Session because agents need state"* é um anti-pattern de `sweet-spot.md`.
43
+ > Só adicione histórico quando o critério acima aponta para ele.
28
44
 
29
45
  ---
30
46
 
31
47
  ## A API
32
48
 
33
- **Pacote:** `Microsoft.Agents.AI` (base; já requerido por `ai-agents-setup`).
49
+ **Pacote:** `Microsoft.Agents.AI` 1.20.0 (base; já requerido por `ai-agents-setup`).
50
+
51
+ **Tipos e membros — medidos por reflexão sobre as assemblies do pin em 2026-09-08:**
52
+
53
+ | Tipo | Onde | O que é |
54
+ |---|---|---|
55
+ | `AgentSession` | `Microsoft.Agents.AI.Abstractions` | Container de estado da conversa. Abstrato; tem `StateBag`. Criado por `agent.CreateSessionAsync()` |
56
+ | `ChatClientAgentSession` | `Microsoft.Agents.AI` | A `AgentSession` do `ChatClientAgent`; acrescenta `ConversationId` (o id gerenciado pelo serviço, quando há) |
57
+ | `ChatHistoryProvider` | `Microsoft.Agents.AI.Abstractions` | Classe **abstrata** a estender. Pontos de override: `ProvideChatHistoryAsync(InvokingContext, ct)` e `StoreChatHistoryAsync(InvokedContext, ct)` (ambos `protected`). Declare também `StateKeys` |
58
+ | `ProviderSessionState<TState>` | `Microsoft.Agents.AI.Abstractions` | Estado **por sessão**, com `GetOrInitializeState(session)` / `SaveState(session, state)` e um `StateKey` |
59
+ | `InMemoryChatHistoryProvider` | `Microsoft.Agents.AI.Abstractions` | Implementação embutida. `sealed`. Aceita `ChatReducer` e `ReducerTriggerEvent` |
60
+ | `IChatReducer`, `MessageCountingChatReducer`, `SummarizingChatReducer` | `Microsoft.Extensions.AI` | Redutores de histórico |
61
+ | `ChatClientAgentOptions` | `Microsoft.Agents.AI` | Aceita `ChatHistoryProvider`, `AIContextProviders`, e as três flags de conflito (`Throw/Warn/ClearOnChatHistoryProviderConflict`) |
62
+ | `agent.SerializeSessionAsync(session, …)` / `agent.DeserializeSessionAsync(JsonElement, …)` | `AIAgent` | Serialização da sessão. **São `…Async` e devolvem `ValueTask`** — não existe forma síncrona |
63
+
64
+ > **Correções contra a versão anterior deste standard, todas medidas:** `AgentThread` e `GetNewThread()` **não existem** em `Microsoft.Agents.AI` 1.20.0 (renomeados para `AgentSession` / `CreateSessionAsync` ainda no ciclo pré-GA, `preview.260128.1` e `preview.260205.1`); `CosmosChatHistoryProvider` **não está** em `Microsoft.Agents.AI` nem em `Microsoft.Agents.AI.Abstractions` 1.20.0 — se existir, é de outro pacote, e este standard não afirma qual.
65
+
66
+ ### A forma de um provider de conversa própria
67
+
68
+ ```csharp
69
+ using Microsoft.Agents.AI;
70
+ using Microsoft.Extensions.AI;
71
+
72
+ public sealed class ConversationStore : ChatHistoryProvider
73
+ {
74
+ public const string ConversationIdStateKey = "app.conversation.id";
75
+
76
+ private readonly IConversationStore _store; // o acervo do PROJETO
77
+ private readonly ProviderSessionState<string> _conversationId; // estado POR SESSÃO
78
+
79
+ public ConversationStore(IConversationStore store)
80
+ {
81
+ ArgumentNullException.ThrowIfNull(store);
82
+ _store = store;
83
+ _conversationId = new ProviderSessionState<string>(NewConversationId, ConversationIdStateKey);
84
+ }
85
+
86
+ // Declara a chave que este provider ocupa no estado da sessão — é o que permite
87
+ // ao MAF serializar e retomar uma sessão sem adivinhar o que é de quem.
88
+ public override IReadOnlyList<string> StateKeys => [ConversationIdStateKey];
89
+
90
+ protected override async ValueTask<IEnumerable<ChatMessage>> ProvideChatHistoryAsync(
91
+ InvokingContext context, CancellationToken cancellationToken = default)
92
+ => await _store.LoadAsync(GetConversationId(context.Session!), cancellationToken);
34
93
 
35
- **Tipos confirmados via context7:**
36
- - `AgentSession` — container leve de estado de conversa; obtido via `agent.CreateSessionAsync()`
37
- - `AgentThread` — equivalente para agentes persistentes (PersistentAgentsClient); use `agent.GetNewThread()`
38
- - `ChatClientAgentOptions` — aceita `ChatHistoryProvider` e `AIContextProviders`
39
- - `InMemoryChatHistoryProvider` — implementação embutida de histórico em memória
40
- - `AgentResponse` — tipo retornado por `AIAgent.RunAsync` (non-generic); acesse o texto via `.Text`
94
+ protected override async ValueTask StoreChatHistoryAsync(
95
+ InvokedContext context, CancellationToken cancellationToken = default)
96
+ {
97
+ // Volta que falhou não é gravada: persistir o pedido sozinho deixaria a conversa
98
+ // terminando numa pergunta que o modelo nunca respondeu.
99
+ if (context.InvokeException is not null) return;
100
+
101
+ List<ChatMessage> round = [.. context.RequestMessages ?? [], .. context.ResponseMessages ?? []];
102
+ if (round.Count == 0) return;
103
+
104
+ // Grava SÓ esta volta. Regravar o histórico inteiro a cada turno faz a conversa
105
+ // crescer em progressão geométrica.
106
+ await _store.AppendAsync(GetConversationId(context.Session!), round, cancellationToken);
107
+ }
108
+
109
+ public string GetConversationId(AgentSession session)
110
+ => _conversationId.GetOrInitializeState(session);
111
+
112
+ private static string NewConversationId(AgentSession? session)
113
+ => session is ChatClientAgentSession { ConversationId.Length: > 0 } managed
114
+ ? managed
115
+ : Guid.CreateVersion7().ToString("n"); // ordenável no tempo; NewGuid fragmenta índice
116
+ }
117
+ ```
118
+
119
+ ### A invariante de instância — o erro que só aparece em produção
120
+
121
+ **O provider é UMA instância compartilhada por todas as sessões.** Ele não pode ter campo de estado por conversa. O único estado por sessão vive em `ProviderSessionState<TState>`, **dentro da `AgentSession`**.
122
+
123
+ Um campo de instância guardando "a conversa atual" é como o histórico de um usuário aparece na tela de outro — e a falha **não** aparece em teste de uma sessão só: aparece sob concorrência, em produção, como vazamento de dado alheio. O canário é um teste com **duas sessões concorrentes** sobre o **mesmo** provider.
124
+
125
+ ### Histórico embutido, quando o critério aponta para ele
41
126
 
42
127
  ```csharp
43
- // Construção do agente com histórico em memória
44
128
  AIAgent agent = _modelRegistry.GetChatClient("text-default")
45
129
  .AsAIAgent(new ChatClientAgentOptions
46
130
  {
47
131
  ChatOptions = new() { Instructions = "You are a helpful assistant." },
48
- ChatHistoryProvider = new InMemoryChatHistoryProvider(),
132
+ ChatHistoryProvider = new InMemoryChatHistoryProvider(new InMemoryChatHistoryProviderOptions
133
+ {
134
+ ChatReducer = new MessageCountingChatReducer(20),
135
+ ReducerTriggerEvent = ChatReducerTriggerEvent.AfterMessageAdded,
136
+ }),
49
137
  });
50
138
  ```
51
139
 
@@ -59,6 +147,10 @@ using Microsoft.Extensions.AI;
59
147
 
60
148
  // ── 1. Registrar o agente conversacional no DI ──
61
149
  // Program.cs
150
+ builder.Services.AddSingleton<IConversationStore, PostgresConversationStore>();
151
+ builder.Services.AddSingleton<ChatHistoryProvider>(sp =>
152
+ new ConversationStore(sp.GetRequiredService<IConversationStore>())); // UMA instância
153
+
62
154
  builder.Services.AddSingleton<AIAgent>(sp =>
63
155
  {
64
156
  var registry = sp.GetRequiredService<ModelRegistry>();
@@ -66,40 +158,37 @@ builder.Services.AddSingleton<AIAgent>(sp =>
66
158
  .AsAIAgent(new ChatClientAgentOptions
67
159
  {
68
160
  ChatOptions = new() { Instructions = "You are a helpful customer support assistant." },
69
- // InMemoryChatHistoryProvider: histórico vive em memória, por session.
70
- // Seguro registrar como parte do singleton AIAgent: cada AgentSession criada via
71
- // agent.CreateSessionAsync() isola o histórico de sua conversa — conversas distintas
72
- // não compartilham estado. O provider em si é stateless; o estado fica na session.
73
- // Para persistência entre restarts, substitua por um provider customizado (ex: DB).
74
- ChatHistoryProvider = new InMemoryChatHistoryProvider(),
161
+ ChatHistoryProvider = sp.GetRequiredService<ChatHistoryProvider>(),
75
162
  });
76
163
  });
77
164
 
78
- // ── 2. Criar uma session por conversa (ex: por conexão SignalR / por request de "start chat") ──
79
- // ChatController.cs ou ChatHub.cs
80
- public class ChatService(AIAgent _agent)
165
+ // ── 2. Uma session por conversa (por conexão SignalR, por "start chat") ──
166
+ public class ChatService(AIAgent _agent, ConversationStore _history)
81
167
  {
82
- // Uma session por conversa ativa — armazene no escopo do usuário (cache, memória da conexão)
83
- public async Task<AgentSession> StartConversationAsync()
84
- => await _agent.CreateSessionAsync();
168
+ public async Task<AgentSession> StartConversationAsync(string conversationId)
169
+ {
170
+ var session = await _agent.CreateSessionAsync();
171
+ _history.BindConversation(session, conversationId); // a conversa JÁ EXISTE como registro
172
+ return session;
173
+ }
85
174
 
86
- // Cada mensagem do usuário passa a mesma session
87
175
  public async Task<string> SendMessageAsync(AgentSession session, string userMessage)
88
176
  {
89
177
  AgentResponse response = await _agent.RunAsync(userMessage, session);
90
178
  return response.Text;
91
179
  }
180
+
181
+ // Retomar depois de um restart: a sessão é dado, não objeto vivo.
182
+ public async Task<AgentSession> ResumeAsync(JsonElement serialized)
183
+ => await _agent.DeserializeSessionAsync(serialized);
92
184
  }
93
185
 
94
- // ── 3. Uso no controller/hub ──
95
- // Primeiro turno
96
- AgentSession session = await chatService.StartConversationAsync();
186
+ // ── 3. Uso ──
187
+ AgentSession session = await chatService.StartConversationAsync(conversation.Id);
97
188
  string reply1 = await chatService.SendMessageAsync(session, "Meu pedido #1234 está atrasado.");
98
- // reply1: "Vou verificar o pedido #1234 para você..."
99
-
100
- // Segundo turno — o agente lembra do contexto anterior
101
189
  string reply2 = await chatService.SendMessageAsync(session, "E quando foi despachado?");
102
- // reply2: "O pedido #1234 foi despachado em..." ← contexto mantido pela session
190
+ // O contexto do segundo turno veio do ACERVO DO PROJETO — legível por relatório, por auditoria,
191
+ // e apagável a pedido do titular.
103
192
  ```
104
193
 
105
194
  ---
@@ -108,21 +197,15 @@ string reply2 = await chatService.SendMessageAsync(session, "E quando foi despac
108
197
 
109
198
  O histórico cresce a cada turno. Quando estoura o context window do modelo, as chamadas falham ou truncam silenciosamente.
110
199
 
111
- ### Estratégias
112
-
113
200
  | Estratégia | Quando usar | Como implementar |
114
201
  |------------|-------------|------------------|
115
- | **Sliding window** | Conversas longas com contexto recente suficiente | Limitar `InMemoryChatHistoryProvider` a N mensagens mais recentes |
116
- | **Token budget** | Modelos com context window pequeno | Contar tokens acumulados; truncar quando ultrapassa threshold |
117
- | **Summarization** | Histórico precisa de contexto antigo comprimido | Agente periódico que resume N turnos anteriores em uma mensagem única |
118
-
119
- > **Custom history management:** Para o caso comum, `InMemoryChatHistoryProvider` cobre a
120
- > necessidade de histórico em memória por sessão. Se o projeto exigir truncation customizada
121
- > (ex: sliding window limitando a N mensagens mais recentes ou por token budget), o mecanismo
122
- > de extensão correto — seja subclasse de `ChatHistoryProvider`, um `IChatReducer`, ou outro
123
- > ponto de override — deve ser verificado contra a versão instalada de `Microsoft.Agents.AI`.
124
- > Consulte a documentação MAF atual antes de implementar um provider customizado, pois a API
125
- > exata de extensão não foi confirmada na versão GA e pode variar entre releases.
202
+ | **Sliding window** | Conversas longas com contexto recente suficiente | `MessageCountingChatReducer(n)` no `InMemoryChatHistoryProvider`, ou um `LIMIT` na query do provider próprio |
203
+ | **Token budget** | Modelos com context window pequeno | Contar tokens acumulados no provider próprio e truncar |
204
+ | **Summarization** | Histórico precisa de contexto antigo comprimido | `SummarizingChatReducer`, ou compaction (`ai-agents-context-providers` §Compaction) |
205
+
206
+ **Com conversa própria, a truncation é query, não middleware.** `ProvideChatHistoryAsync` devolve o que a query devolveu — `ORDER BY created_at DESC LIMIT n` já é o sliding window, e é auditável no banco. `IChatReducer` existe para o caminho embutido.
207
+
208
+ **Grave só a volta corrente.** `StoreChatHistoryAsync` recebe `RequestMessages` + `ResponseMessages` **daquela** volta; regravar o histórico completo a cada turno é crescimento geométrico do acervo.
126
209
 
127
210
  ---
128
211
 
@@ -130,31 +213,44 @@ O histórico cresce a cada turno. Quando estoura o context window do modelo, as
130
213
 
131
214
  | Anti-pattern | Problema |
132
215
  |-------------|----------|
133
- | Adicionar session em agente one-shot (gerador, executor) | Complexidade desnecessária; estado nunca é usado |
216
+ | **Estado por sessão em campo do provider** | O provider é **uma** instância para todas as sessões. Um campo `_currentConversation` faz o histórico de um usuário aparecer para outro. Estado por sessão vive em `ProviderSessionState<TState>`, com `StateKey` declarado em `StateKeys`. A falha não aparece em teste de uma sessão só |
217
+ | **`ConversationId` / `previous_response_id` como fronteira de autorização** | Esses ids são escopados à **chave da API**, não ao usuário: quem tem o id e a chave lê a conversa. Mapeie o id do cliente para o id do serviço e **verifique o dono** antes de retomar |
218
+ | Adicionar histórico em agente one-shot (gerador, executor) | Complexidade desnecessária; estado nunca é usado |
134
219
  | Histórico ilimitado sem truncation | Context window estoura; custo aumenta linearmente com a conversa |
135
220
  | Compartilhar uma `AgentSession` entre múltiplos usuários | Histórico de um usuário vaza para outro |
136
- | Usar `InMemoryChatHistoryProvider` sem criar uma `AgentSession` por conversa | Sem `AgentSession` por conversa, o histórico é compartilhado entre todos os usuários; a isolation depende de `AgentSession` — sempre crie uma session por conversa via `agent.CreateSessionAsync()` |
137
- | Usar `AgentThread` (PersistentAgentsClient) sem necessidade | `AgentThread` requer hosted agent service; prefira `AgentSession` com direct model |
221
+ | Usar `InMemoryChatHistoryProvider` sem criar uma `AgentSession` por conversa | A isolation depende de `AgentSession` — sempre uma session por conversa, via `agent.CreateSessionAsync()` |
222
+ | Gravar a volta que falhou | Sem resposta, a conversa termina numa pergunta não respondida; a volta seguinte a repete e o usuário se vê duplicado |
223
+ | Deixar `store` ligado tendo histórico próprio | Duas cópias da conversa, uma delas fora do seu controle de retenção |
224
+
225
+ > **Nota de migração (histórico, não API viva):** `AgentThread` → `AgentSession` e `GetNewThread()` → `CreateSessionAsync()` aconteceram **antes** do GA de 2026-04-02. Código escrito contra os nomes antigos não compila com o pin. Não são alternativas: são nomes mortos.
138
226
 
139
227
  ---
140
228
 
141
229
  ## Checklist (verifiable by morph-eval)
142
230
 
143
- - [ ] `AgentSession` usada somente em agentes conversacionais com UI de chat real
144
- - [ ] `InMemoryChatHistoryProvider` (ou equivalente) registrado em `ChatClientAgentOptions`
231
+ - [ ] A escolha da fonte de histórico foi feita pela tabela de critério — e está escrita em `decisions.md` quando não foi a conversa própria
232
+ - [ ] O provider de histórico é registrado como **uma** instância compartilhada
233
+ - [ ] Nenhum campo de instância do provider guarda estado de conversa; o que é por sessão está em `ProviderSessionState<TState>` e declarado em `StateKeys`
234
+ - [ ] Existe teste com **duas sessões concorrentes** sobre o mesmo provider
145
235
  - [ ] Uma `AgentSession` por conversa/usuário — nunca compartilhada
146
- - [ ] Estratégia de truncation definida (sliding window, token budget ou summarization)
147
- - [ ] Agentes one-shot (gerador, executor, classificador) **não** recebem session
236
+ - [ ] `ConversationId` nunca é usado como prova de autorização; o dono é verificado antes de retomar
237
+ - [ ] `store: false` quando o histórico é próprio
238
+ - [ ] Estratégia de truncation definida (query com `LIMIT`, reducer ou summarization)
239
+ - [ ] Agentes one-shot (gerador, executor, classificador) **não** recebem histórico
240
+ - [ ] Nenhuma ocorrência de `AgentThread` / `GetNewThread()` no código
148
241
 
149
242
  ---
150
243
 
151
244
  ## References
152
245
 
153
- - `ai-agents-setup` — packages e DI base
246
+ - `ai-agents-setup` — packages, DI base, `store: false`
154
247
  - `ai-agents-sweet-spot` — decisão de quando adicionar estado ao agente
155
- - `ai-agents-middleware-patterns` (Onda 2) — pipeline de contexto e middleware
156
- - MAF Conversations docs: https://learn.microsoft.com/en-us/agent-framework/agents/conversations/
248
+ - `ai-agents-context-providers` — a mesma invariante de instância, e compaction
249
+ - `ai-agents-middleware-patterns` — pipeline e middleware
250
+ - Reference implementation (compila contra o pin): `templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/ConversationStore.cs`
251
+ - MAF Conversations / storage: https://learn.microsoft.com/en-us/agent-framework/agents/conversations/storage (`ms.date` 2026-07-01)
252
+ - MAF self-hosting: https://learn.microsoft.com/en-us/agent-framework/hosting/self-hosting/ (`ms.date` 2026-08-17)
157
253
 
158
254
  ---
159
255
 
160
- *MORPH-SPEC by Polymorphism Tech — ai-agents/agent-session.md v1.0 (2026-05-19)*
256
+ *MORPH-SPEC by Polymorphism Tech — ai-agents/agent-session.md v2.0 (2026-09-08)*