@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,288 @@
1
+ using Microsoft.Extensions.AI;
2
+ using OpenAI.Images;
3
+
4
+ namespace Morph.AiKit.Media.Providers;
5
+
6
+ /// <summary>
7
+ /// Adaptador de imagem da OpenAI. <b><c>internal</c></b> — ver <see cref="IMediaProvider"/>.
8
+ /// </summary>
9
+ /// <remarks>
10
+ /// <para>
11
+ /// A chamada passa pela abstracao <see cref="IImageGenerator"/> de
12
+ /// <c>Microsoft.Extensions.AI</c>, e nao pelo <c>ImageClient</c> cru, para que o pipeline
13
+ /// nao fique acoplado ao SDK de um provider. A ponte oficial
14
+ /// (<c>Microsoft.Extensions.AI.OpenAI.AsIImageGenerator()</c>) <b>nao esta no pin deste
15
+ /// kit</b>, entao o adaptador <see cref="OpenAIImageGenerator"/> vive aqui, escrito a mao
16
+ /// sobre o <c>ImageClient</c>. Trocar por <c>AsIImageGenerator()</c> e uma linha, no dia em
17
+ /// que o pacote entrar em <c>framework/ai-pin.json</c>.
18
+ /// </para>
19
+ /// <para>
20
+ /// <b>Medido contra o pin em 2026-09-08, nao suposto:</b>
21
+ /// <c>Microsoft.Extensions.AI.IImageGenerator</c> carrega <c>[Experimental("MEAI001")]</c>
22
+ /// e herda <c>IDisposable</c>; <c>ImageGenerationRequest</c> tem <c>Prompt</c> e
23
+ /// <c>OriginalImages</c> (<c>IEnumerable&lt;AIContent&gt;</c>), e tambem e experimental;
24
+ /// <c>ImageGenerationOptions</c> <b>nao</b> tem propriedade tipada para
25
+ /// <c>quality</c>/<c>background</c>/<c>input_fidelity</c> — por isso a qualidade viaja em
26
+ /// <c>AdditionalProperties</c> e e este adaptador que a traduz para o SDK.
27
+ /// </para>
28
+ /// </remarks>
29
+ internal sealed class OpenAIImageProvider : IMediaProvider
30
+ {
31
+ /// <summary>A chave sob a qual a qualidade viaja em <c>AdditionalProperties</c>.</summary>
32
+ internal const string QualityKey = "quality";
33
+
34
+ private readonly IMediaClientFactory _clients;
35
+
36
+ public OpenAIImageProvider(IMediaClientFactory clients)
37
+ {
38
+ ArgumentNullException.ThrowIfNull(clients);
39
+ _clients = clients;
40
+ }
41
+
42
+ /// <inheritdoc />
43
+ public string Provider => "openai";
44
+
45
+ /// <inheritdoc />
46
+ public bool Supports(MediaKind kind) => kind == MediaKind.Image;
47
+
48
+ /// <inheritdoc />
49
+ public async Task<MediaResult<MediaArtifact>> ProduceAsync(
50
+ MediaRequest request,
51
+ MediaAliasBinding binding,
52
+ CancellationToken cancellationToken)
53
+ {
54
+ ArgumentNullException.ThrowIfNull(request);
55
+ ArgumentNullException.ThrowIfNull(binding);
56
+
57
+ var client = _clients.CreateOpenAiImageClient(binding);
58
+ if (client is null)
59
+ {
60
+ return MediaResult<MediaArtifact>.Fail(
61
+ MediaErrorCode.ProviderFailure,
62
+ $"alias '{binding.Alias}': a fabrica de clientes nao construiu um ImageClient para o provider 'openai'.");
63
+ }
64
+
65
+ #pragma warning disable MEAI001 // IImageGenerator/ImageGenerationRequest sao experimentais: a superficie pode mudar entre menores. Risco assumido por escrito.
66
+ using IImageGenerator generator = new OpenAIImageGenerator(client);
67
+
68
+ var generationRequest = new ImageGenerationRequest { Prompt = request.Prompt };
69
+
70
+ if (request.References.Count > 0)
71
+ {
72
+ // OriginalImages e o gancho de EDICAO: preserva o produto real em vez de
73
+ // recria-lo. Gerar do zero quando a foto existe inventa material, medida ou cor
74
+ // que o produto nao tem — o claim visual falso que o AI Act art. 50 mira.
75
+ generationRequest.OriginalImages =
76
+ [.. request.References.Select(r => new DataContent(r.Bytes, r.MediaType))];
77
+ }
78
+
79
+ var options = new Microsoft.Extensions.AI.ImageGenerationOptions
80
+ {
81
+ ModelId = binding.Model,
82
+ MediaType = request.Options.MediaType,
83
+ Count = request.Options.Count,
84
+ };
85
+
86
+ if (request.Options is { Width: { } width, Height: { } height })
87
+ {
88
+ options.ImageSize = new System.Drawing.Size(width, height);
89
+ }
90
+
91
+ if (request.Options.Quality is { } quality)
92
+ {
93
+ // Nao ha propriedade tipada na 10.9.0 — medido. Vai por AdditionalProperties, e
94
+ // o adaptador acima e quem traduz para o SDK.
95
+ options.AdditionalProperties = new AdditionalPropertiesDictionary
96
+ {
97
+ [QualityKey] = quality.ToString(),
98
+ };
99
+ }
100
+
101
+ try
102
+ {
103
+ var response = await generator
104
+ .GenerateAsync(generationRequest, options, cancellationToken)
105
+ .ConfigureAwait(false);
106
+
107
+ var data = response.Contents.OfType<DataContent>().FirstOrDefault();
108
+ if (data is null)
109
+ {
110
+ return MediaResult<MediaArtifact>.Fail(
111
+ MediaErrorCode.ProviderFailure,
112
+ $"alias '{binding.Alias}': a resposta nao trouxe DataContent. Uma resposta so com URL " +
113
+ "seria um arquivo que expira, e este pipeline guarda BYTES.");
114
+ }
115
+
116
+ return MediaResult<MediaArtifact>.Ok(new MediaArtifact(
117
+ MediaKind.Image,
118
+ data.MediaType,
119
+ data.Data,
120
+ RevisedPrompt: (response.RawRepresentation as GeneratedImage)?.RevisedPrompt,
121
+ ResponseId: null,
122
+ // Os bytes chegam como o provider os produziu: nenhum re-encode entre a
123
+ // resposta e o blob. E o que mantem a credencial C2PA viva.
124
+ C2paPreserved: true));
125
+ }
126
+ #pragma warning restore MEAI001
127
+ catch (System.ClientModel.ClientResultException ex)
128
+ {
129
+ // Bloqueio de moderacao e resposta DEFINITIVA, nunca erro tecnico: retentar
130
+ // gasta para receber o mesmo "nao". A distincao mora aqui, no unico ponto que
131
+ // ve o codigo HTTP.
132
+ return ex.Status == 400
133
+ ? MediaResult<MediaArtifact>.Fail(
134
+ MediaErrorCode.PolicyBlocked,
135
+ $"alias '{binding.Alias}': o provider recusou o pedido (HTTP 400): {ex.Message}")
136
+ : MediaResult<MediaArtifact>.Fail(
137
+ MediaErrorCode.ProviderFailure,
138
+ $"alias '{binding.Alias}': falha tecnica (HTTP {ex.Status}): {ex.Message}");
139
+ }
140
+ }
141
+ }
142
+
143
+ /// <summary>
144
+ /// <see cref="IImageGenerator"/> escrito a mao sobre o <c>ImageClient</c> do SDK da OpenAI.
145
+ /// </summary>
146
+ /// <remarks>
147
+ /// Existe porque <c>Microsoft.Extensions.AI.OpenAI</c> — que traz
148
+ /// <c>AsIImageGenerator()</c> — nao esta em <c>framework/ai-pin.json</c>, e acrescentar
149
+ /// pacote e mexer no pin. O contrato imitado e o mesmo: <c>OriginalImages</c> vazio vira
150
+ /// <c>GenerateImageAsync</c>; com referencia, vira <c>GenerateImageEditAsync</c>, que e o
151
+ /// caminho que PRESERVA o produto real.
152
+ /// </remarks>
153
+ // OPENAI001 entra junto, e nao por preguica: GeneratedImageQuality.{Low,Medium,High}Quality
154
+ // e ImageEditOptions.Quality carregam o diagnostico de "evaluation only" no OpenAI 2.13.0 —
155
+ // medido pelo compilador, nao suposto. Suprimir os dois com o motivo escrito e o item 3 do
156
+ // checklist de ai-agents/modalities-image-gen.md.
157
+ #pragma warning disable MEAI001, OPENAI001
158
+ internal sealed class OpenAIImageGenerator : IImageGenerator
159
+ {
160
+ private readonly ImageClient _client;
161
+
162
+ public OpenAIImageGenerator(ImageClient client)
163
+ {
164
+ ArgumentNullException.ThrowIfNull(client);
165
+ _client = client;
166
+ }
167
+
168
+ public async Task<ImageGenerationResponse> GenerateAsync(
169
+ ImageGenerationRequest request,
170
+ Microsoft.Extensions.AI.ImageGenerationOptions? options,
171
+ CancellationToken cancellationToken = default)
172
+ {
173
+ ArgumentNullException.ThrowIfNull(request);
174
+
175
+ var reference = request.OriginalImages?.OfType<DataContent>().FirstOrDefault();
176
+
177
+ GeneratedImage image = reference is null
178
+ ? (await _client
179
+ .GenerateImageAsync(request.Prompt ?? string.Empty, BuildGenerationOptions(options), cancellationToken)
180
+ .ConfigureAwait(false)).Value
181
+ : (await _client
182
+ .GenerateImageEditAsync(
183
+ new MemoryStream(reference.Data.ToArray()),
184
+ FileNameFor(reference.MediaType),
185
+ request.Prompt ?? string.Empty,
186
+ BuildEditOptions(options),
187
+ cancellationToken)
188
+ .ConfigureAwait(false)).Value;
189
+
190
+ var mediaType = options?.MediaType ?? "image/png";
191
+
192
+ return new ImageGenerationResponse([new DataContent(image.ImageBytes.ToMemory(), mediaType)])
193
+ {
194
+ RawRepresentation = image,
195
+ };
196
+ }
197
+
198
+ public object? GetService(Type serviceType, object? serviceKey = null)
199
+ {
200
+ ArgumentNullException.ThrowIfNull(serviceType);
201
+
202
+ if (serviceKey is not null)
203
+ {
204
+ return null;
205
+ }
206
+
207
+ return serviceType.IsInstanceOfType(_client) ? _client
208
+ : serviceType.IsInstanceOfType(this) ? this
209
+ : null;
210
+ }
211
+
212
+ public void Dispose()
213
+ {
214
+ // O ImageClient nao e IDisposable e o seu tempo de vida e do projeto: a fabrica de
215
+ // clientes cria, o projeto descarta. Descartar aqui seria uma segunda dona do mesmo
216
+ // recurso — foi assim que um cliente vazou de um teste, uma vez.
217
+ }
218
+
219
+ private static OpenAI.Images.ImageGenerationOptions BuildGenerationOptions(
220
+ Microsoft.Extensions.AI.ImageGenerationOptions? options)
221
+ {
222
+ var sdk = new OpenAI.Images.ImageGenerationOptions
223
+ {
224
+ // Bytes, sempre. Uma URL de provider expira, e um caminho quebrado depois e um
225
+ // arquivo pelo qual se pagou e que nao existe mais.
226
+ ResponseFormat = GeneratedImageFormat.Bytes,
227
+ };
228
+
229
+ if (options?.ImageSize is { } size)
230
+ {
231
+ sdk.Size = new GeneratedImageSize(size.Width, size.Height);
232
+ }
233
+
234
+ if (QualityOf(options) is { } quality)
235
+ {
236
+ sdk.Quality = quality;
237
+ }
238
+
239
+ return sdk;
240
+ }
241
+
242
+ private static ImageEditOptions BuildEditOptions(Microsoft.Extensions.AI.ImageGenerationOptions? options)
243
+ {
244
+ var sdk = new ImageEditOptions { ResponseFormat = GeneratedImageFormat.Bytes };
245
+
246
+ if (options?.ImageSize is { } size)
247
+ {
248
+ sdk.Size = new GeneratedImageSize(size.Width, size.Height);
249
+ }
250
+
251
+ if (QualityOf(options) is { } quality)
252
+ {
253
+ sdk.Quality = quality;
254
+ }
255
+
256
+ return sdk;
257
+ }
258
+
259
+ /// <summary>
260
+ /// Traduz a qualidade que viajou em <c>AdditionalProperties</c>. Chave ausente devolve
261
+ /// nulo — e nulo significa "nao envia ao provider", nunca "manda o default do kit".
262
+ /// </summary>
263
+ private static GeneratedImageQuality? QualityOf(Microsoft.Extensions.AI.ImageGenerationOptions? options)
264
+ {
265
+ if (options?.AdditionalProperties is not { } extra
266
+ || !extra.TryGetValue(OpenAIImageProvider.QualityKey, out var raw)
267
+ || raw is null)
268
+ {
269
+ return null;
270
+ }
271
+
272
+ return raw.ToString() switch
273
+ {
274
+ nameof(MediaQuality.Low) => GeneratedImageQuality.LowQuality,
275
+ nameof(MediaQuality.Medium) => GeneratedImageQuality.MediumQuality,
276
+ nameof(MediaQuality.High) => GeneratedImageQuality.HighQuality,
277
+ _ => null,
278
+ };
279
+ }
280
+
281
+ private static string FileNameFor(string? mediaType) => mediaType switch
282
+ {
283
+ "image/jpeg" or "image/jpg" => "reference.jpg",
284
+ "image/webp" => "reference.webp",
285
+ _ => "reference.png",
286
+ };
287
+ }
288
+ #pragma warning restore MEAI001
@@ -0,0 +1,158 @@
1
+ using Google.GenAI.Types;
2
+
3
+ namespace Morph.AiKit.Media.Providers;
4
+
5
+ /// <summary>
6
+ /// Adaptador de video do Veo. <b><c>internal</c></b> — ver <see cref="IMediaProvider"/>.
7
+ /// </summary>
8
+ /// <remarks>
9
+ /// <para>
10
+ /// <b>E o unico caminho de video com SDK .NET oficial</b> depois do desligamento da Sora
11
+ /// (data em <c>ai-agents/media-video.md</c>, secao Deprecacoes). Seedance, Kling e Runway
12
+ /// exigem <c>HttpClient</c> tipado com DTOs proprios, e por isso nao tem adaptador aqui.
13
+ /// </para>
14
+ /// <para>
15
+ /// <b>Assinatura medida contra Google.GenAI 1.21.0, nao lida em blog:</b>
16
+ /// <c>Models.GenerateVideosAsync(string model, GenerateVideosSource source,
17
+ /// GenerateVideosConfig config, CancellationToken)</c> devolve
18
+ /// <c>GenerateVideosOperation</c> — o prompt vai DENTRO de <c>GenerateVideosSource</c>, e
19
+ /// nao como parametro solto. O polling e
20
+ /// <c>Operations.GetAsync(operation, config, ct)</c>, e o veredito e
21
+ /// <c>operation.Done</c>.
22
+ /// </para>
23
+ /// <para>
24
+ /// <b>Os bytes sao baixados AQUI.</b> O Veo retem o arquivo por 2 dias; devolver a URL e
25
+ /// entregar um link que morre. Quando a resposta so traz <c>Uri</c>, este adaptador recusa
26
+ /// com motivo em vez de guardar a URL fingindo que e permanente.
27
+ /// </para>
28
+ /// </remarks>
29
+ internal sealed class VeoVideoProvider : IMediaProvider
30
+ {
31
+ /// <summary>Intervalo entre voltas do polling. ~10 s e o intervalo que a doc do Veo usa.</summary>
32
+ internal static readonly TimeSpan PollInterval = TimeSpan.FromSeconds(10);
33
+
34
+ /// <summary>
35
+ /// Teto de voltas. Existe porque <c>Done</c> que nunca vira <c>true</c> e um caso real,
36
+ /// e um laco sem saida e indistinguivel de um worker travado. 60 voltas cobrem os 6 min
37
+ /// documentados como pior caso, com folga.
38
+ /// </summary>
39
+ internal const int MaxPolls = 60;
40
+
41
+ private readonly IMediaClientFactory _clients;
42
+ private readonly Func<TimeSpan, CancellationToken, Task> _delay;
43
+
44
+ public VeoVideoProvider(IMediaClientFactory clients, Func<TimeSpan, CancellationToken, Task>? delay = null)
45
+ {
46
+ ArgumentNullException.ThrowIfNull(clients);
47
+ _clients = clients;
48
+ _delay = delay ?? Task.Delay;
49
+ }
50
+
51
+ /// <inheritdoc />
52
+ public string Provider => "google";
53
+
54
+ /// <inheritdoc />
55
+ public bool Supports(MediaKind kind) => kind == MediaKind.Video;
56
+
57
+ /// <inheritdoc />
58
+ public async Task<MediaResult<MediaArtifact>> ProduceAsync(
59
+ MediaRequest request,
60
+ MediaAliasBinding binding,
61
+ CancellationToken cancellationToken)
62
+ {
63
+ ArgumentNullException.ThrowIfNull(request);
64
+ ArgumentNullException.ThrowIfNull(binding);
65
+
66
+ var client = _clients.CreateGoogleClient(binding);
67
+ if (client is null)
68
+ {
69
+ return MediaResult<MediaArtifact>.Fail(
70
+ MediaErrorCode.ProviderFailure,
71
+ $"alias '{binding.Alias}': a fabrica de clientes nao construiu um Google.GenAI.Client.");
72
+ }
73
+
74
+ var config = new GenerateVideosConfig
75
+ {
76
+ DurationSeconds = request.Options.DurationSeconds,
77
+ AspectRatio = request.Options.AspectRatio,
78
+ NumberOfVideos = request.Options.Count,
79
+ };
80
+
81
+ if (request.References.Count > 0)
82
+ {
83
+ // O Veo exige 8 s quando ha imagens de referencia. Pedir 4 s COM referencia e
84
+ // requisicao invalida, e descobrir isso em producao custa uma rodada de suporte.
85
+ config.ReferenceImages =
86
+ [
87
+ .. request.References.Select(r => new VideoGenerationReferenceImage
88
+ {
89
+ Image = new Image { ImageBytes = r.Bytes.ToArray(), MimeType = r.MediaType },
90
+ }),
91
+ ];
92
+ }
93
+
94
+ var operation = await client.Models
95
+ .GenerateVideosAsync(
96
+ binding.Model,
97
+ new GenerateVideosSource { Prompt = request.Prompt },
98
+ config,
99
+ cancellationToken)
100
+ .ConfigureAwait(false);
101
+
102
+ for (var poll = 0; operation.Done != true && poll < MaxPolls; poll++)
103
+ {
104
+ await _delay(PollInterval, cancellationToken).ConfigureAwait(false);
105
+ operation = await client.Operations
106
+ .GetAsync(operation, new GetOperationConfig(), cancellationToken)
107
+ .ConfigureAwait(false);
108
+ }
109
+
110
+ if (operation.Done != true)
111
+ {
112
+ return MediaResult<MediaArtifact>.Fail(
113
+ MediaErrorCode.ProviderFailure,
114
+ $"alias '{binding.Alias}': a operacao '{operation.Name}' nao concluiu em {MaxPolls} voltas. " +
115
+ "O id ficou gravado no job: retomar o polling nao paga de novo.");
116
+ }
117
+
118
+ if (operation.Error is { Count: > 0 })
119
+ {
120
+ return MediaResult<MediaArtifact>.Fail(
121
+ MediaErrorCode.ProviderFailure,
122
+ $"alias '{binding.Alias}': a operacao terminou com erro: " +
123
+ string.Join("; ", operation.Error.Select(e => $"{e.Key}={e.Value}")));
124
+ }
125
+
126
+ var response = operation.Response;
127
+
128
+ if (response?.RaiMediaFilteredCount is > 0)
129
+ {
130
+ // Bloqueio de moderacao. No Veo ele NAO cobra — e nao vira retry, porque
131
+ // retentar recebe o mesmo "nao".
132
+ return MediaResult<MediaArtifact>.Fail(
133
+ MediaErrorCode.PolicyBlocked,
134
+ $"alias '{binding.Alias}': {response.RaiMediaFilteredCount} saida(s) bloqueada(s) por politica: " +
135
+ string.Join("; ", response.RaiMediaFilteredReasons ?? []));
136
+ }
137
+
138
+ var video = response?.GeneratedVideos?.Select(g => g.Video).FirstOrDefault(v => v is not null);
139
+
140
+ if (video?.VideoBytes is not { Length: > 0 } bytes)
141
+ {
142
+ return MediaResult<MediaArtifact>.Fail(
143
+ MediaErrorCode.ProviderFailure,
144
+ $"alias '{binding.Alias}': a operacao concluiu sem bytes de video" +
145
+ (video?.Uri is { Length: > 0 } uri
146
+ ? $" (so a URI '{uri}', que o Veo apaga em 2 dias). Baixe os bytes antes de marcar Generated."
147
+ : "."));
148
+ }
149
+
150
+ return MediaResult<MediaArtifact>.Ok(new MediaArtifact(
151
+ MediaKind.Video,
152
+ video.MimeType ?? "video/mp4",
153
+ bytes,
154
+ RevisedPrompt: null,
155
+ ResponseId: operation.Name,
156
+ C2paPreserved: true));
157
+ }
158
+ }
@@ -0,0 +1,29 @@
1
+ namespace Morph.AiKit.Middleware;
2
+
3
+ /// <summary>
4
+ /// Para onde vai o custo de cada volta ao modelo. <b>A costura de saida do
5
+ /// <see cref="UsageCostMiddleware"/></b>: o kit calcula, o projeto decide onde guardar
6
+ /// (tabela, metrica, log estruturado, fila).
7
+ /// </summary>
8
+ /// <remarks>
9
+ /// <para>
10
+ /// <b>Por que uma interface de um metodo so e nao um evento nem um logger:</b> custo e
11
+ /// dado de negocio, nao diagnostico. Um projeto multi-tenant precisa somar por conta e por
12
+ /// mes; um <c>ILogger</c> nao devolve soma. A interface e minima de proposito — quem quiser
13
+ /// um logger implementa um sink de duas linhas.
14
+ /// </para>
15
+ /// <para>
16
+ /// <b>Contrato de execucao:</b> <see cref="Record"/> e chamado no caminho da resposta,
17
+ /// <b>sincronamente</b>, uma vez por volta ao modelo. Uma implementacao que faca I/O
18
+ /// bloqueante aqui paga esse custo na latencia de cada resposta — enfileire e persista fora
19
+ /// do caminho quente. E ela pode ser chamada de varias threads ao mesmo tempo (um mesmo
20
+ /// pipeline atende varias conversas): a implementacao e responsavel pela propria seguranca
21
+ /// sob concorrencia.
22
+ /// </para>
23
+ /// </remarks>
24
+ public interface IUsageCostSink
25
+ {
26
+ /// <summary>Publica o custo de uma volta ao modelo.</summary>
27
+ /// <param name="record">O registro ja calculado. Nunca nulo.</param>
28
+ void Record(UsageCostRecord record);
29
+ }