@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,208 @@
1
+ using System.Runtime.CompilerServices;
2
+ using Microsoft.Extensions.AI;
3
+ using Morph.AiKit.Providers;
4
+
5
+ namespace Morph.AiKit.Middleware;
6
+
7
+ /// <summary>
8
+ /// Middleware de <see cref="IChatClient"/> que le o <c>Usage</c> da resposta, aplica a
9
+ /// tarifa do alias e publica uma linha de custo em <see cref="IUsageCostSink"/>.
10
+ /// </summary>
11
+ /// <remarks>
12
+ /// <para>
13
+ /// <b>Onde ele entra no pipeline:</b> <b>ACIMA</b> da invocacao de funcoes, com a
14
+ /// telemetria de chat abaixo dela (<c>usage-cost -&gt; function-invocation -&gt;
15
+ /// OpenTelemetry -&gt; cliente do provider</c>). Na pratica: a
16
+ /// <c>AgentFactory.BuildChatPipeline</c> registra o encaixe de custo <b>antes</b> de
17
+ /// <c>UseFunctionInvocation</c>, e no <c>ChatClientBuilder</c> o primeiro registrado e o
18
+ /// mais <b>externo</b>. A ordem nao e estetica, e o motivo e o
19
+ /// <c>FunctionInvokingChatClient</c> (FICC): acima dele o middleware ve <b>uma</b> resposta
20
+ /// cujo <c>Usage</c> ja vem com o total de todas as voltas de tool (medido: duas voltas de
21
+ /// 10/4 e 30/6 chegam como <c>in=40, out=10</c>) e publica <b>uma</b> linha por chamada.
22
+ /// Abaixo dele veria as respostas parciais — e leria o mesmo objeto <c>UsageDetails</c> que
23
+ /// o proprio FICC <b>muta</b> para acumular, o que faria a mesma conta dar resultado
24
+ /// diferente conforme a hora de ler. Isso e medido, nao argumentado, em
25
+ /// <c>AgentFactoryTests.ThePipelineOrderIsUsageCostAboveFunctionInvocationAndTelemetryBelowIt</c>
26
+ /// (sequencia <c>usage-cost:enter -&gt; telemetry:enter/exit x2 -&gt; usage-cost:exit</c>) e
27
+ /// em <c>AgentFactoryTests.UsageCostAboveFunctionInvocationSeesTheUsageOfEveryToolRoundSummedOnce</c>.
28
+ /// A montagem do pipeline e da <c>AgentFactory</c> (T10); daqui so depende a extensao
29
+ /// <see cref="UsageCostChatClientBuilderExtensions.UseUsageCost"/>.
30
+ /// </para>
31
+ /// <para>
32
+ /// <b>Nota de errata:</b> o <c>spec.md</c> sec. 3.1 desta feature prescrevia a seta
33
+ /// literal <c>function-invocation -&gt; usage-cost -&gt; OpenTelemetry</c>, que se le ao
34
+ /// contrario do que esta implementado aqui. A divergencia foi medida na T10 sec. 3.2 e esta
35
+ /// registrada como <b>Errata E9</b> no proprio <c>spec.md</c> — o corpo do plano e
36
+ /// append-only e continua com a seta antiga; a verdade e esta.
37
+ /// </para>
38
+ /// <para>
39
+ /// <b>A conta e a do <see cref="ModelPricing.ComputeCostUsd"/>, nao uma segunda.</b> Este
40
+ /// tipo nao contem aritmetica de tarifa: ele converte <c>Usage</c> em argumentos, chama a
41
+ /// conta que ja existe e carimba o resultado. Reescrever a formula aqui daria dois numeros
42
+ /// para o mesmo custo — que e literalmente a dor no nome desta epica (em ProspectPRO a
43
+ /// conta esta repetida em cinco agentes).
44
+ /// </para>
45
+ /// <para>
46
+ /// <b>Nunca lanca por causa de tarifa.</b> Alias sem tarifa e caminho previsto: sai
47
+ /// <c>CostUsd = 0</c> com <see cref="UsageCostStatus.Waived"/> e o motivo escrito no
48
+ /// record. Inventar tarifa e pior que nao ter. E resposta sem <c>Usage</c> sai como
49
+ /// <see cref="UsageCostStatus.UsageMissing"/> — visivel, em vez de silenciosa.
50
+ /// </para>
51
+ /// </remarks>
52
+ public sealed class UsageCostMiddleware : DelegatingChatClient
53
+ {
54
+ private readonly ModelAlias _alias;
55
+ private readonly IUsageCostSink _sink;
56
+ private readonly TimeProvider _timeProvider;
57
+
58
+ /// <summary>Monta o middleware sobre um cliente interno.</summary>
59
+ /// <param name="innerClient">O proximo elo do pipeline.</param>
60
+ /// <param name="alias">
61
+ /// O alias que atende este cliente — de onde vem a tarifa e o nome que vai no record.
62
+ /// </param>
63
+ /// <param name="sink">Para onde as linhas de custo vao.</param>
64
+ /// <param name="timeProvider">
65
+ /// Relogio. Nulo usa <see cref="TimeProvider.System"/>. Injetavel porque o standard
66
+ /// <c>backend-dotnet-testing</c> proibe <c>DateTimeOffset.UtcNow</c> direto num tipo
67
+ /// testavel — sem isso, o instante do record e intestavel.
68
+ /// </param>
69
+ public UsageCostMiddleware(
70
+ IChatClient innerClient,
71
+ ModelAlias alias,
72
+ IUsageCostSink sink,
73
+ TimeProvider? timeProvider = null)
74
+ : base(innerClient)
75
+ {
76
+ ArgumentNullException.ThrowIfNull(alias);
77
+ ArgumentNullException.ThrowIfNull(sink);
78
+
79
+ _alias = alias;
80
+ _sink = sink;
81
+ _timeProvider = timeProvider ?? TimeProvider.System;
82
+ }
83
+
84
+ /// <inheritdoc />
85
+ public override async Task<ChatResponse> GetResponseAsync(
86
+ IEnumerable<ChatMessage> messages,
87
+ ChatOptions? options = null,
88
+ CancellationToken cancellationToken = default)
89
+ {
90
+ var response = await base.GetResponseAsync(messages, options, cancellationToken)
91
+ .ConfigureAwait(false);
92
+
93
+ Publish(response.Usage);
94
+
95
+ return response;
96
+ }
97
+
98
+ /// <inheritdoc />
99
+ /// <remarks>
100
+ /// No streaming o <c>Usage</c> chega como <see cref="UsageContent"/> avulso, tipicamente
101
+ /// no ultimo update — e pode chegar em mais de um pedaco. Os pedacos sao somados e a
102
+ /// linha de custo sai <b>uma unica vez</b>, ao fim da enumeracao: emitir por update daria
103
+ /// N linhas para uma volta so.
104
+ /// </remarks>
105
+ public override async IAsyncEnumerable<ChatResponseUpdate> GetStreamingResponseAsync(
106
+ IEnumerable<ChatMessage> messages,
107
+ ChatOptions? options = null,
108
+ [EnumeratorCancellation] CancellationToken cancellationToken = default)
109
+ {
110
+ UsageDetails? accumulated = null;
111
+
112
+ await foreach (var update in base.GetStreamingResponseAsync(messages, options, cancellationToken)
113
+ .ConfigureAwait(false))
114
+ {
115
+ foreach (var content in update.Contents)
116
+ {
117
+ if (content is UsageContent usage)
118
+ {
119
+ (accumulated ??= new UsageDetails()).Add(usage.Details);
120
+ }
121
+ }
122
+
123
+ yield return update;
124
+ }
125
+
126
+ Publish(accumulated);
127
+ }
128
+
129
+ private void Publish(UsageDetails? usage)
130
+ {
131
+ var at = _timeProvider.GetUtcNow();
132
+
133
+ if (usage is null || (usage.InputTokenCount is null && usage.OutputTokenCount is null))
134
+ {
135
+ // Sem relato de uso nao ha o que tarifar. A linha sai assim mesmo, marcada: um
136
+ // custo que ninguem consegue medir precisa aparecer, nao sumir.
137
+ _sink.Record(new UsageCostRecord(_alias.Name, 0, 0, null, 0m, at)
138
+ {
139
+ Status = UsageCostStatus.UsageMissing,
140
+ });
141
+ return;
142
+ }
143
+
144
+ var input = usage.InputTokenCount ?? 0L;
145
+ var output = usage.OutputTokenCount ?? 0L;
146
+ var cached = usage.CachedInputTokenCount;
147
+
148
+ if (_alias.Pricing is not { } pricing)
149
+ {
150
+ // Caminho previsto, nunca excecao: o alias declarou por escrito que nao tem
151
+ // tarifa (o registry recusa a carga de um alias sem tarifa E sem dispensa).
152
+ _sink.Record(new UsageCostRecord(_alias.Name, input, output, cached, 0m, at)
153
+ {
154
+ Status = UsageCostStatus.Waived,
155
+ PricingWaiver = _alias.PricingWaiver,
156
+ });
157
+ return;
158
+ }
159
+
160
+ // Um provider que reporte 'cached' maior que 'input' esta se contradizendo; a conta
161
+ // do T8 recusa esse par. Aqui o dado inconsistente vira lacuna declarada, e nao uma
162
+ // excecao que derruba a resposta do usuario por causa de um contador.
163
+ if (cached > input)
164
+ {
165
+ _sink.Record(new UsageCostRecord(_alias.Name, input, output, cached, 0m, at)
166
+ {
167
+ Status = UsageCostStatus.UsageMissing,
168
+ });
169
+ return;
170
+ }
171
+
172
+ _sink.Record(new UsageCostRecord(
173
+ _alias.Name,
174
+ input,
175
+ output,
176
+ cached,
177
+ pricing.ComputeCostUsd(input, output, cached),
178
+ at)
179
+ {
180
+ Status = UsageCostStatus.Computed,
181
+ });
182
+ }
183
+ }
184
+
185
+ /// <summary>
186
+ /// Registro do <see cref="UsageCostMiddleware"/> no pipeline de <see cref="IChatClient"/>.
187
+ /// </summary>
188
+ public static class UsageCostChatClientBuilderExtensions
189
+ {
190
+ /// <summary>
191
+ /// Insere a contabilizacao de custo no pipeline, com a tarifa do alias dado.
192
+ /// </summary>
193
+ /// <param name="builder">O builder do pipeline.</param>
194
+ /// <param name="alias">Alias que atende este cliente.</param>
195
+ /// <param name="sink">Destino das linhas de custo.</param>
196
+ /// <param name="timeProvider">Relogio; nulo usa <see cref="TimeProvider.System"/>.</param>
197
+ /// <returns>O proprio builder, para encadear.</returns>
198
+ public static ChatClientBuilder UseUsageCost(
199
+ this ChatClientBuilder builder,
200
+ ModelAlias alias,
201
+ IUsageCostSink sink,
202
+ TimeProvider? timeProvider = null)
203
+ {
204
+ ArgumentNullException.ThrowIfNull(builder);
205
+
206
+ return builder.Use(inner => new UsageCostMiddleware(inner, alias, sink, timeProvider));
207
+ }
208
+ }
@@ -0,0 +1,95 @@
1
+ using Morph.AiKit.Providers;
2
+
3
+ namespace Morph.AiKit.Middleware;
4
+
5
+ /// <summary>
6
+ /// Como o custo de uma volta ao modelo ficou conhecido. Existe para que
7
+ /// <see cref="UsageCostRecord.CostUsd"/> possa ser um <see cref="decimal"/> nao-anulavel
8
+ /// <b>sem que zero passe a significar tres coisas diferentes</b>.
9
+ /// </summary>
10
+ /// <remarks>
11
+ /// A dor que esta feature nomeia e <c>cost_usd</c> saindo nulo. Trocar o nulo por um zero
12
+ /// mudo seria trocar um defeito por outro pior — zero soma, nulo nao. Aqui o valor e sempre
13
+ /// um numero e o status diz se aquele numero e uma medicao, uma decisao ou uma lacuna.
14
+ /// </remarks>
15
+ public enum UsageCostStatus
16
+ {
17
+ /// <summary>
18
+ /// Tarifa do alias aplicada sobre uso reportado pelo provider. O unico status em que
19
+ /// <see cref="UsageCostRecord.CostUsd"/> e uma <b>medicao</b> — e o unico que pode
20
+ /// entrar numa soma de fatura sem ressalva.
21
+ /// </summary>
22
+ Computed = 0,
23
+
24
+ /// <summary>
25
+ /// O alias nao tem tarifa e <b>tem dispensa escrita</b>
26
+ /// (<c>ModelAlias.PricingWaiver</c>). Custo zero por decisao registrada — modelo local,
27
+ /// por exemplo, onde a conta e a maquina e nao o token. O motivo viaja em
28
+ /// <see cref="UsageCostRecord.PricingWaiver"/>: um zero aqui nunca e anonimo.
29
+ /// </summary>
30
+ Waived = 1,
31
+
32
+ /// <summary>
33
+ /// O provider <b>nao reportou</b> <c>Usage</c> nesta volta. Os tokens sao desconhecidos,
34
+ /// logo o custo tambem e: o zero em <see cref="UsageCostRecord.CostUsd"/> e ausencia de
35
+ /// medicao, <b>nao</b> gratuidade. Some com <see cref="Computed"/> apenas ciente disso.
36
+ /// </summary>
37
+ UsageMissing = 2,
38
+ }
39
+
40
+ /// <summary>
41
+ /// O custo de uma volta ao modelo, ja calculado. <b>Uma linha por resposta</b>, pronta para
42
+ /// virar registro de banco, metrica ou linha de fatura.
43
+ /// </summary>
44
+ /// <remarks>
45
+ /// <para>
46
+ /// <b><see cref="CostUsd"/> nunca e nulo — por construcao do tipo.</b> Esse e o ponto
47
+ /// inteiro: a dor catalogada na issue e um <c>cost_usd</c> nulo atravessando tres camadas
48
+ /// e aparecendo como buraco no relatorio. A ausencia de tarifa deixou de poder chegar ate
49
+ /// aqui por esquecimento: o <c>ModelRegistry</c> (T8) <b>recusa a carga</b> de um alias que
50
+ /// nao declare <c>pricing</c> nem <c>pricingWaiver</c>. Logo, quando este record sai com
51
+ /// <see cref="UsageCostStatus.Waived"/>, existe necessariamente um motivo escrito em
52
+ /// <see cref="PricingWaiver"/>.
53
+ /// </para>
54
+ /// <para>
55
+ /// <b>A conta nao mora aqui.</b> Ela mora em <see cref="ModelPricing.ComputeCostUsd"/>
56
+ /// (T8), e o <see cref="UsageCostMiddleware"/> apenas a chama. Uma segunda aritmetica do
57
+ /// mesmo custo e o defeito que esta epica tem no nome: em ProspectPRO ela esta repetida
58
+ /// literalmente em cinco agentes, e duas copias da mesma conta divergem — a divergencia
59
+ /// aparece na fatura.
60
+ /// </para>
61
+ /// </remarks>
62
+ /// <param name="Alias">O alias do <c>ModelRegistry</c> que atendeu a volta.</param>
63
+ /// <param name="InputTokens">Tokens de entrada reportados. Zero quando nao houve relato.</param>
64
+ /// <param name="OutputTokens">Tokens de saida reportados. Zero quando nao houve relato.</param>
65
+ /// <param name="CachedInputTokens">
66
+ /// Tokens de entrada servidos do cache do provider, ou nulo quando o provider nao reporta.
67
+ /// E <b>subconjunto</b> de <paramref name="InputTokens"/>, nunca uma parcela a mais.
68
+ /// </param>
69
+ /// <param name="CostUsd">
70
+ /// Custo em USD. Nunca nulo; leia <see cref="Status"/> antes de somar.
71
+ /// </param>
72
+ /// <param name="At">Instante da volta, vindo do <see cref="TimeProvider"/> injetado.</param>
73
+ public sealed record UsageCostRecord(
74
+ string Alias,
75
+ long InputTokens,
76
+ long OutputTokens,
77
+ long? CachedInputTokens,
78
+ decimal CostUsd,
79
+ DateTimeOffset At)
80
+ {
81
+ /// <summary>Como o custo ficou conhecido. Ver <see cref="UsageCostStatus"/>.</summary>
82
+ public required UsageCostStatus Status { get; init; }
83
+
84
+ /// <summary>
85
+ /// O motivo escrito de o alias nao ter tarifa, copiado de
86
+ /// <c>ModelAlias.PricingWaiver</c>. Preenchido <b>somente</b> com
87
+ /// <see cref="UsageCostStatus.Waived"/>.
88
+ /// </summary>
89
+ public string? PricingWaiver { get; init; }
90
+
91
+ /// <summary>
92
+ /// Se <see cref="CostUsd"/> e uma medicao — o unico caso em que somar e honesto.
93
+ /// </summary>
94
+ public bool IsMeasuredCost => Status == UsageCostStatus.Computed;
95
+ }
@@ -0,0 +1,38 @@
1
+ <Project Sdk="Microsoft.NET.Sdk">
2
+
3
+ <PropertyGroup>
4
+ <RootNamespace>Morph.AiKit</RootNamespace>
5
+ <AssemblyName>Morph.AiKit</AssemblyName>
6
+ </PropertyGroup>
7
+
8
+ <!--
9
+ A REGRA DURA DE ai-agents/media-pipeline.md, presa por acessibilidade.
10
+
11
+ Morph.AiKit.Media.IMediaProvider e os tres adaptadores de provider sao `internal`: um
12
+ handler do projeto consumidor NAO consegue nomear o tipo que produz bytes, e o codigo
13
+ nao compila. A unica superficie publica e IMediaGenerator.EnqueueAsync, que devolve um
14
+ id de job.
15
+
16
+ Esta linha e a UNICA excecao, e ela existe para que a suite possa asserir a
17
+ acessibilidade por reflexao e exercitar o worker com um provider fake. Acrescentar um
18
+ segundo InternalsVisibleTo aqui — para o projeto consumidor, "so para testar" — desfaz
19
+ o mecanismo inteiro; o teste MediaAccessibilityTests grita se os tipos virarem publicos,
20
+ mas nao consegue ver quem mais foi convidado para dentro.
21
+ -->
22
+ <ItemGroup>
23
+ <InternalsVisibleTo Include="Morph.AiKit.Tests" />
24
+ </ItemGroup>
25
+
26
+ <!-- Sem atributo Version: as versoes vem de Directory.Packages.props (gerado do pin). -->
27
+ <ItemGroup>
28
+ <PackageReference Include="Microsoft.Agents.AI" />
29
+ <PackageReference Include="Microsoft.Extensions.AI" />
30
+ <PackageReference Include="OpenAI" />
31
+ <PackageReference Include="Google.GenAI" />
32
+ <PackageReference Include="ModelContextProtocol" />
33
+ <PackageReference Include="Microsoft.Extensions.AI.Evaluation" />
34
+ <PackageReference Include="Microsoft.Extensions.AI.Evaluation.Quality" />
35
+ <PackageReference Include="Microsoft.Extensions.AI.Evaluation.Reporting" />
36
+ </ItemGroup>
37
+
38
+ </Project>
@@ -0,0 +1,119 @@
1
+ using Microsoft.Agents.AI;
2
+ using Microsoft.Extensions.AI;
3
+ using Morph.AiKit.Agents;
4
+
5
+ namespace Morph.AiKit.Observability;
6
+
7
+ /// <summary>
8
+ /// Liga as GenAI semantic conventions nos dois niveis do kit — agente e chat client — com
9
+ /// <b>um guard contra span duplicado em cada um</b>.
10
+ /// </summary>
11
+ /// <remarks>
12
+ /// <para>
13
+ /// <b>O que foi medido no pin (Microsoft.Agents.AI 1.20.0), e nao suposto:</b>
14
+ /// </para>
15
+ /// <list type="bullet">
16
+ /// <item>
17
+ /// Uma invocacao instrumentada produz <c>invoke_agent</c> (raiz) e <c>chat</c> (filho).
18
+ /// Duas camadas de instrumentacao no MESMO nivel produzem o span daquele nivel duas
19
+ /// vezes: dois <c>OpenTelemetryChatClient</c> dao dois <c>chat</c>; dois
20
+ /// <c>OpenTelemetryAgent</c> dao dois <c>invoke_agent</c>.
21
+ /// </item>
22
+ /// <item>
23
+ /// <c>GetService</c> atravessa a cadeia de delegates nos dois niveis — e por isso que
24
+ /// "ja existe instrumentacao aqui embaixo?" e uma pergunta respondivel, e nao um
25
+ /// palpite. E o predicado dos dois guards.
26
+ /// </item>
27
+ /// <item>
28
+ /// O MAF 1.20.0 tem um guard proprio, mas ele so alcanca o pipeline que o
29
+ /// <c>ChatClientAgent</c> monta sozinho. A <c>AgentFactory</c> monta o proprio
30
+ /// (<c>UseProvidedChatClientAsIs = true</c>) para poder posicionar o custo e ajustar o
31
+ /// tool calling — e nesse arranjo o slot do MAF nao existe. Medido: agente
32
+ /// instrumentado + pipeline proprio sem estas extensoes = <b>zero</b> spans de chat.
33
+ /// O guard daqui nao duplica o do MAF; ele cobre o pipeline que o MAF nao ve.
34
+ /// </item>
35
+ /// </list>
36
+ /// </remarks>
37
+ public static class MorphOpenTelemetryExtensions
38
+ {
39
+ /// <summary>
40
+ /// Instrumenta o pipeline de chat. Aplicado pela <c>AgentFactory</c> ABAIXO do
41
+ /// <c>FunctionInvokingChatClient</c>, que e onde o MAF 1.20.0 documenta que a
42
+ /// instrumentacao tem de ficar para o span de chat fechar antes das tools.
43
+ /// </summary>
44
+ /// <remarks>
45
+ /// O guard vive na decisao de <see cref="ShouldInstrument"/>: com
46
+ /// <see cref="MorphTelemetryOptions.InstrumentChatClient"/> nulo (o default), um
47
+ /// pipeline que ja carrega um <see cref="OpenTelemetryChatClient"/> e devolvido intacto.
48
+ /// </remarks>
49
+ public static ChatClientBuilder UseMorphTelemetry(this ChatClientBuilder builder, MorphTelemetryOptions options)
50
+ {
51
+ ArgumentNullException.ThrowIfNull(builder);
52
+ ArgumentNullException.ThrowIfNull(options);
53
+
54
+ return builder.Use(inner => ShouldInstrument(inner, options)
55
+ ? new OpenTelemetryChatClient(inner, logger: null, sourceName: options.SourceName)
56
+ {
57
+ EnableSensitiveData = options.EnableSensitiveData,
58
+ }
59
+ : inner);
60
+ }
61
+
62
+ /// <summary>
63
+ /// Instrumenta o agente — o span <c>invoke_agent</c>, o mais externo, que cobre a
64
+ /// invocacao inteira. Um agente que ja e instrumentado e devolvido intacto.
65
+ /// </summary>
66
+ public static AIAgentBuilder UseMorphTelemetry(this AIAgentBuilder builder, MorphTelemetryOptions options)
67
+ {
68
+ ArgumentNullException.ThrowIfNull(builder);
69
+ ArgumentNullException.ThrowIfNull(options);
70
+
71
+ return builder.Use(inner => inner.GetService(typeof(OpenTelemetryAgent)) is not null
72
+ ? inner
73
+ : new OpenTelemetryAgent(inner, options.SourceName)
74
+ {
75
+ EnableSensitiveData = options.EnableSensitiveData,
76
+ });
77
+ }
78
+
79
+ /// <summary>
80
+ /// Preenche os dois encaixes de telemetria da <see cref="AgentFactoryOptions"/> de uma
81
+ /// vez, respeitando <see cref="AgentSpecOptions.EnableSensitiveTelemetry"/> quando a
82
+ /// spec opinou.
83
+ /// </summary>
84
+ /// <remarks>
85
+ /// A fabrica e dona da POSICAO de cada encaixe; esta extensao so diz o que ocupa cada
86
+ /// um. E por aqui que a T10 e a T12 se encontram sem uma referenciar a outra.
87
+ /// <para>
88
+ /// <c>EnableSensitiveTelemetry</c> nulo na spec significa "nao opinei" e mantem o valor
89
+ /// destas opcoes; <c>false</c> significa "decidi que nao" e vence. A diferenca entre os
90
+ /// dois e preservada de proposito desde a T7.
91
+ /// </para>
92
+ /// </remarks>
93
+ public static AgentFactoryOptions WithMorphTelemetry(
94
+ this AgentFactoryOptions factoryOptions,
95
+ MorphTelemetryOptions options)
96
+ {
97
+ ArgumentNullException.ThrowIfNull(factoryOptions);
98
+ ArgumentNullException.ThrowIfNull(options);
99
+
100
+ return factoryOptions with
101
+ {
102
+ ConfigureChatTelemetry = (builder, spec, _) => builder.UseMorphTelemetry(ForSpec(options, spec)),
103
+ ConfigureAgentTelemetry = (builder, spec, _) => builder.UseMorphTelemetry(ForSpec(options, spec)),
104
+ };
105
+ }
106
+
107
+ private static MorphTelemetryOptions ForSpec(MorphTelemetryOptions options, AgentSpec spec)
108
+ => spec.Options.EnableSensitiveTelemetry is { } sensitive
109
+ ? options with { EnableSensitiveData = sensitive }
110
+ : options;
111
+
112
+ /// <summary>
113
+ /// <b>O guard.</b> Nulo = instrumenta so o que ainda nao esta instrumentado;
114
+ /// <c>true</c> = instrumenta sempre (e duplica, quando ja havia); <c>false</c> = nunca.
115
+ /// </summary>
116
+ private static bool ShouldInstrument(IChatClient inner, MorphTelemetryOptions options)
117
+ => options.InstrumentChatClient
118
+ ?? inner.GetService(typeof(OpenTelemetryChatClient)) is null;
119
+ }
@@ -0,0 +1,82 @@
1
+ namespace Morph.AiKit.Observability;
2
+
3
+ /// <summary>
4
+ /// O que o kit precisa saber para emitir telemetria GenAI: sob que <c>ActivitySource</c>,
5
+ /// com ou sem conteudo sensivel, e — a decisao que este tipo existe para carregar — se a
6
+ /// instrumentacao do chat client deve ser aplicada.
7
+ /// </summary>
8
+ /// <remarks>
9
+ /// <para>
10
+ /// <b>Por que <see cref="SourceName"/> e obrigatorio.</b> O standard
11
+ /// <c>ai-agents-observability-patterns</c> manda usar
12
+ /// <c>AgentOpenTelemetryConsts.DefaultSourceName</c>. No <c>Microsoft.Agents.AI</c> 1.20.0
13
+ /// esse tipo <b>nao e publico</b> (apurado por reflexao sobre o assembly do pin: a classe
14
+ /// se chama <c>OpenTelemetryConsts</c> e e <c>internal</c>). Um kit que quisesse "usar a
15
+ /// constante do MAF" so poderia repetir o texto dela — e um literal copiado envelhece em
16
+ /// silencio na primeira vez que o pacote o mudar. Entao o nome e do projeto: e a MESMA
17
+ /// string que ele passa para <c>AddSource(...)</c> na configuracao do OpenTelemetry, e o
18
+ /// span do agente e o span de chat nascem sob ela, juntos.
19
+ /// </para>
20
+ /// </remarks>
21
+ public sealed record MorphTelemetryOptions
22
+ {
23
+ private readonly string _sourceName = string.Empty;
24
+
25
+ /// <summary>
26
+ /// Nome do <c>ActivitySource</c> dos spans deste kit. Branco e rejeitado na construcao:
27
+ /// um source sem nome e telemetria que ninguem consegue registrar nem coletar.
28
+ /// </summary>
29
+ public required string SourceName
30
+ {
31
+ get => _sourceName;
32
+ init
33
+ {
34
+ ArgumentException.ThrowIfNullOrWhiteSpace(value, nameof(SourceName));
35
+ _sourceName = value;
36
+ }
37
+ }
38
+
39
+ /// <summary>
40
+ /// Se prompt, resposta, argumentos e resultados de tool entram nos spans. <c>false</c>
41
+ /// por padrao — e o standard exige <c>false</c> fora de dev/staging, porque esse
42
+ /// conteudo e PII do cliente.
43
+ /// </summary>
44
+ public bool EnableSensitiveData { get; init; }
45
+
46
+ /// <summary>
47
+ /// Se o pipeline de chat deve receber instrumentacao propria. <b>Tres valores, e o
48
+ /// default e o guard.</b>
49
+ /// </summary>
50
+ /// <remarks>
51
+ /// <list type="table">
52
+ /// <listheader><term>Valor</term><description>O que faz</description></listheader>
53
+ /// <item>
54
+ /// <term><c>null</c> (default)</term>
55
+ /// <description>
56
+ /// <b>Instrumenta somente se ainda nao houver instrumentacao no pipeline.</b> A
57
+ /// deteccao e <c>GetService(typeof(OpenTelemetryChatClient))</c>, que atravessa a
58
+ /// cadeia de delegates (medido). E este ramo, e so ele, que impede o span de chat
59
+ /// duplicado.
60
+ /// </description>
61
+ /// </item>
62
+ /// <item>
63
+ /// <term><c>true</c></term>
64
+ /// <description>
65
+ /// Instrumenta sempre. Sobre um pipeline ja instrumentado, produz <b>dois</b>
66
+ /// spans <c>chat</c> por invocacao — medido, e pinado por teste. Existe para
67
+ /// documentar o risco, nao para ser ligado.
68
+ /// </description>
69
+ /// </item>
70
+ /// <item>
71
+ /// <term><c>false</c></term>
72
+ /// <description>
73
+ /// Nunca instrumenta. Com a <c>AgentFactory</c>, que monta o proprio pipeline
74
+ /// (<c>UseProvidedChatClientAsIs = true</c>), isso significa <b>nenhum</b> span de
75
+ /// <c>chat</c>: o slot que o MAF reservaria e ativaria sozinho nao existe nesse
76
+ /// arranjo. Escolha consciente, nao default.
77
+ /// </description>
78
+ /// </item>
79
+ /// </list>
80
+ /// </remarks>
81
+ public bool? InstrumentChatClient { get; init; }
82
+ }
@@ -0,0 +1,33 @@
1
+ using Microsoft.Extensions.AI;
2
+
3
+ namespace Morph.AiKit.Providers;
4
+
5
+ /// <summary>
6
+ /// Constroi o <see cref="IChatClient"/> de um alias. E <b>a</b> costura do kit: o unico
7
+ /// ponto em que o codigo toca um provider de verdade.
8
+ /// </summary>
9
+ /// <remarks>
10
+ /// <para>
11
+ /// O <see cref="ModelRegistry"/> nao sabe construir cliente de provider nenhum — de
12
+ /// proposito. Quem sabe e uma implementacao desta interface, e e por isso que a suite do
13
+ /// kit roda sem rede e sem chave de API: em teste, a fabrica devolve
14
+ /// <c>FakeChatClient</c>. Num projeto, ela e o <c>switch</c> por
15
+ /// <see cref="ModelAlias.Provider"/> descrito no standard
16
+ /// <c>ai-agents-providers-model-registry</c> (<c>openai</c> e <c>ollama</c> de saida,
17
+ /// os demais como branch nova).
18
+ /// </para>
19
+ /// <para>
20
+ /// <b>Quem descarta o cliente:</b> o <see cref="ModelRegistry"/>. A fabrica cria; o
21
+ /// registry memoiza por alias e descarta no proprio <c>Dispose</c>. Uma fabrica que
22
+ /// guardasse e reaproveitasse clientes por fora criaria uma segunda cache, e duas caches
23
+ /// da mesma coisa e como um cliente vazado sobrevive a um teste.
24
+ /// </para>
25
+ /// </remarks>
26
+ public interface IProviderClientFactory
27
+ {
28
+ /// <summary>
29
+ /// Cria o cliente do alias dado. Chamado <b>uma vez por alias</b> pelo
30
+ /// <see cref="ModelRegistry"/>; o resultado e memoizado.
31
+ /// </summary>
32
+ IChatClient CreateChatClient(ModelAlias alias);
33
+ }