@polymorphism-tech/morph-spec 8.37.1 → 8.40.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 (317) hide show
  1. package/CLAUDE.md +37 -13
  2. package/README.md +2 -2
  3. package/bin/morph-spec.js +75 -49
  4. package/claude-plugin.json +1 -1
  5. package/docs/CHEATSHEET.md +1 -1
  6. package/docs/QUICKSTART.md +1 -1
  7. package/framework/CLAUDE.md +6 -5
  8. package/framework/MORPH.md +25 -22
  9. package/framework/agents.json +96 -36
  10. package/framework/docs/CLI.md +54 -17
  11. package/framework/evals/rubrics/code-quality.md +5 -0
  12. package/framework/evals/rubrics/condensed.md +6 -2
  13. package/framework/evals/rubrics/contracts.md +20 -0
  14. package/framework/evals/rubrics/test-coverage.md +17 -6
  15. package/framework/hooks/README.md +9 -3
  16. package/framework/hooks/claude-code/core/graph-refresh-kick.js +52 -0
  17. package/framework/hooks/claude-code/core/telemetry-log.js +172 -87
  18. package/framework/hooks/claude-code/core/validate-completion.js +16 -90
  19. package/framework/hooks/claude-code/core/worktree-context.js +10 -0
  20. package/framework/hooks/shared/command-tokens.js +96 -0
  21. package/framework/hooks/shared/git-exclude.js +44 -0
  22. package/framework/hooks/shared/git-paths.js +52 -0
  23. package/framework/hooks/shared/graph-freshness.js +380 -0
  24. package/framework/hooks/shared/graph-refresh.js +416 -0
  25. package/framework/hooks/shared/morph-cli.js +17 -5
  26. package/framework/hooks/shared/redact-secrets.js +55 -0
  27. package/framework/hooks/shared/telemetry-logger.js +25 -2
  28. package/framework/hooks/shared/transcript-usage.js +80 -0
  29. package/framework/mcp/registry.json +33 -2
  30. package/framework/rubrics/backend.json +2 -2
  31. package/framework/rubrics/default.json +2 -2
  32. package/framework/rubrics/frontend.json +2 -2
  33. package/framework/rules/csharp-standards.md +1 -0
  34. package/framework/rules/infrastructure-standards.md +0 -1
  35. package/framework/rules/morph-workflow.md +10 -4
  36. package/framework/rules/nextjs-standards.md +1 -0
  37. package/framework/schemas/config.schema.json +41 -1
  38. package/framework/schemas/feature.schema.json +5 -1
  39. package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
  40. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
  41. package/framework/skills/core/morph-apply/SKILL.md +40 -11
  42. package/framework/skills/core/morph-brainstorming/SKILL.md +16 -7
  43. package/framework/skills/core/morph-eval/SKILL.md +1 -1
  44. package/framework/skills/core/morph-hotfix/SKILL.md +1 -1
  45. package/framework/skills/core/morph-implement/SKILL.md +44 -10
  46. package/framework/skills/core/morph-media/SKILL.md +1 -1
  47. package/framework/skills/core/morph-plan/SKILL.md +73 -15
  48. package/framework/skills/core/morph-proposal/SKILL.md +1 -1
  49. package/framework/skills/core/morph-review/SKILL.md +51 -13
  50. package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
  51. package/framework/skills/core/morph-standards/SKILL.md +1 -1
  52. package/framework/skills/core/morph-uiux/SKILL.md +39 -13
  53. package/framework/standards/STANDARDS.json +189 -14
  54. package/framework/standards/ai-agents/context-providers.md +16 -26
  55. package/framework/standards/ai-agents/durable-workflows-hitl.md +15 -21
  56. package/framework/standards/ai-agents/modalities-image-gen.md +21 -25
  57. package/framework/standards/ai-agents/modalities-speech-to-text.md +4 -15
  58. package/framework/standards/ai-agents/modalities-text-to-speech.md +2 -11
  59. package/framework/standards/ai-agents/modalities-vision.md +1 -18
  60. package/framework/standards/ai-agents/prompt-sources.md +0 -4
  61. package/framework/standards/ai-agents/testing-ai.md +2 -1
  62. package/framework/standards/architecture/code-comments.md +100 -0
  63. package/framework/standards/backend/dotnet/testing.md +22 -0
  64. package/framework/standards/backend/integrations/neon-auth/neon-auth.md +63 -50
  65. package/framework/standards/frontend/admin-app/data-table.md +562 -0
  66. package/framework/standards/frontend/admin-app/feedback.md +236 -0
  67. package/framework/standards/frontend/admin-app/forms.md +232 -0
  68. package/framework/standards/frontend/admin-app/page-structure.md +203 -0
  69. package/framework/standards/frontend/design-system/ai-image-generation.md +5 -5
  70. package/framework/standards/frontend/nextjs/components.md +37 -58
  71. package/framework/standards/frontend/nextjs/data-fetching.md +1 -0
  72. package/framework/standards/frontend/nextjs/forms.md +31 -30
  73. package/framework/standards/frontend/nextjs/state-management.md +2 -1
  74. package/framework/standards/frontend/nextjs/testing.md +18 -0
  75. package/framework/standards/integration/mcp/mcp-tools.md +48 -117
  76. package/framework/templates/code/dotnet/abstractions/result.cs +0 -2
  77. package/framework/templates/code/dotnet/ai-agents/AgentBootstrap.cs.template +26 -39
  78. package/framework/templates/code/dotnet/ai-agents/EmbeddingService.cs.template +28 -68
  79. package/framework/templates/code/dotnet/ai-agents/ModelRegistry.cs.template +99 -117
  80. package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +2 -44
  81. package/framework/templates/code/dotnet/ai-agents/ResilientToolMiddleware.cs.template +40 -61
  82. package/framework/templates/code/dotnet/ai-agents/VectorSearchTool.cs.template +54 -107
  83. package/framework/templates/code/dotnet/ai-agents/model-registry.json.template +53 -58
  84. package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +192 -281
  85. package/framework/templates/code/dotnet/database/migration.cs +49 -83
  86. package/framework/templates/code/dotnet/database/vector-entity.cs +2 -46
  87. package/framework/templates/code/dotnet/extensions/result-extensions.cs +0 -2
  88. package/framework/templates/code/dotnet/feature/validator.cs.hbs +11 -15
  89. package/framework/templates/code/dotnet/jobs/agent.cs +3 -51
  90. package/framework/templates/code/dotnet/jobs/job.cs +2 -97
  91. package/framework/templates/code/dotnet/test.cs +2 -87
  92. package/framework/templates/code/typescript/contracts.ts +140 -167
  93. package/framework/templates/context/design-system.md +3 -3
  94. package/framework/templates/docs/proposal.md +11 -0
  95. package/framework/templates/docs/spec.md +15 -0
  96. package/framework/templates/docs/ui-mockups.md +115 -98
  97. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentApi.cs +1 -48
  98. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactory.cs +3 -79
  99. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactoryOptions.cs +1 -70
  100. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpec.cs +1 -47
  101. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpecOptions.cs +2 -99
  102. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/AiKitAssemblyMarker.cs +0 -6
  103. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/ConversationStore.cs +3 -88
  104. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/IConversationStore.cs +1 -41
  105. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/InMemoryConversationStore.cs +0 -21
  106. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/CountingChatClient.cs +1 -25
  107. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalAssertion.cs +2 -63
  108. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheMissException.cs +0 -30
  109. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheOptions.cs +1 -52
  110. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheStamp.cs +3 -78
  111. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalFixture.cs +4 -109
  112. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalMode.cs +0 -22
  113. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalQualityEvaluators.cs +1 -36
  114. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalScenario.cs +2 -57
  115. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalSummary.cs +0 -75
  116. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/OfflineChatClient.cs +2 -59
  117. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/ShortPathResponseCache.cs +4 -111
  118. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaGenerator.cs +0 -34
  119. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaProvider.cs +1 -57
  120. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaArtifact.cs +0 -19
  121. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaDisclosure.cs +2 -74
  122. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaGenerator.cs +2 -33
  123. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaIdempotencyKey.cs +1 -43
  124. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJob.cs +1 -96
  125. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobId.cs +0 -13
  126. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobState.cs +0 -27
  127. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaPricing.cs +0 -33
  128. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaProvenance.cs +0 -31
  129. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaRequest.cs +3 -75
  130. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaResult.cs +0 -42
  131. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaReview.cs +0 -39
  132. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaSeams.cs +1 -55
  133. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaStore.cs +3 -59
  134. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MorphMedia.cs +0 -46
  135. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/GoogleImageProvider.cs +3 -28
  136. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/OpenAIImageProvider.cs +7 -61
  137. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/VeoVideoProvider.cs +2 -37
  138. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/IUsageCostSink.cs +1 -23
  139. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostMiddleware.cs +2 -82
  140. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostRecord.cs +1 -68
  141. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphOpenTelemetryExtensions.cs +1 -62
  142. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphTelemetryOptions.cs +2 -62
  143. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/IProviderClientFactory.cs +1 -25
  144. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelAlias.cs +0 -124
  145. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelRegistry.cs +1 -73
  146. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs +1 -66
  147. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaPlan.cs +0 -41
  148. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentFactoryTests.cs +2 -112
  149. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentSpecTests.cs +2 -43
  150. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ConversationStoreTests.cs +5 -110
  151. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/DeltaIngestTests.cs +7 -103
  152. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalAssertionTests.cs +1 -42
  153. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheMissTests.cs +1 -30
  154. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheStampTests.cs +1 -19
  155. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFailuresTests.cs +0 -48
  156. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFixtureTests.cs +1 -29
  157. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalRefreshTests.cs +2 -38
  158. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalWorkspace.cs +1 -14
  159. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/KitEvals.cs +4 -69
  160. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/OfflineChatClientTests.cs +1 -10
  161. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClient.cs +1 -57
  162. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClientTests.cs +0 -26
  163. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeClock.cs +1 -19
  164. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeMediaProvider.cs +0 -32
  165. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeProviderClientFactory.cs +0 -14
  166. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeUsageCostSink.cs +0 -24
  167. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/InMemoryMediaStore.cs +0 -32
  168. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAccessibilityTests.cs +0 -37
  169. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAliasIsNotAnAgentTests.cs +0 -24
  170. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +0 -78
  171. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaGeneratorTests.cs +0 -53
  172. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaIdempotencyKeyTests.cs +0 -44
  173. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaJobStateTests.cs +0 -44
  174. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaReviewTests.cs +0 -19
  175. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaStoreTests.cs +0 -24
  176. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ModelRegistryTests.cs +6 -48
  177. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/SkeletonSmokeTests.cs +1 -13
  178. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/TelemetryTests.cs +2 -71
  179. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/UsageCostMiddlewareTests.cs +5 -100
  180. package/framework/templates/feature/decisions.md +124 -122
  181. package/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +39 -43
  182. package/framework/templates/frontend/nextjs/env.mjs.hbs +29 -32
  183. package/framework/templates/frontend/nextjs/page.tsx.hbs +21 -22
  184. package/framework/templates/frontend/nextjs/use-feature.ts.hbs +42 -54
  185. package/framework/templates/integrations/asaas-client.cs +332 -387
  186. package/framework/templates/integrations/asaas-webhook.cs +290 -351
  187. package/framework/templates/integrations/neon-auth-config.cs +9 -105
  188. package/framework/templates/project/validate.js +97 -120
  189. package/package.json +2 -2
  190. package/src/commands/dashboard/dashboard.js +80 -53
  191. package/src/commands/graph/affected.js +4 -3
  192. package/src/commands/graph/build.js +109 -18
  193. package/src/commands/graph/explain.js +8 -5
  194. package/src/commands/graph/status.js +14 -8
  195. package/src/commands/mcp/mcp-setup.js +37 -9
  196. package/src/commands/observability/cost.js +148 -18
  197. package/src/commands/project/doctor.js +85 -15
  198. package/src/commands/project/init.js +6 -3
  199. package/src/commands/project/install-plugin-cmd.js +1 -1
  200. package/src/commands/project/update.js +30 -0
  201. package/src/commands/project/worktree.js +73 -90
  202. package/src/commands/state/advance.js +18 -0
  203. package/src/commands/state/approve.js +15 -0
  204. package/src/commands/state/archive.js +62 -9
  205. package/src/commands/state/finish.js +62 -14
  206. package/src/commands/state/gate-check.js +8 -1
  207. package/src/commands/state/gate-decision.js +8 -4
  208. package/src/commands/state/report-check.js +90 -9
  209. package/src/commands/state/usecase.js +66 -0
  210. package/src/commands/tasks/dag.js +17 -2
  211. package/src/commands/validation/validate-feature.js +6 -1
  212. package/src/commands/validation/verify.js +20 -1
  213. package/src/dashboard/app/App.jsx +80 -16
  214. package/src/dashboard/app/components/ActivityFeed.jsx +172 -0
  215. package/src/dashboard/app/components/CommandPalette.jsx +155 -0
  216. package/src/dashboard/app/components/DetailPanel.jsx +47 -11
  217. package/src/dashboard/app/components/EntityLink.jsx +55 -0
  218. package/src/dashboard/app/components/ErrorBoundary.jsx +54 -0
  219. package/src/dashboard/app/components/FlowGraph.jsx +19 -17
  220. package/src/dashboard/app/components/KnowledgeMarkdown.jsx +53 -0
  221. package/src/dashboard/app/components/Markdown.jsx +47 -0
  222. package/src/dashboard/app/components/PhaseRail.jsx +111 -0
  223. package/src/dashboard/app/components/SearchFilter.jsx +40 -22
  224. package/src/dashboard/app/components/Sidebar.jsx +146 -37
  225. package/src/dashboard/app/hooks/useMorphQuery.js +54 -0
  226. package/src/dashboard/app/hooks/usePref.js +38 -0
  227. package/src/dashboard/app/lib/format.js +69 -0
  228. package/src/dashboard/app/lib/phases.js +56 -0
  229. package/src/dashboard/app/lib/project.js +50 -0
  230. package/src/dashboard/app/pages/Activity.jsx +24 -0
  231. package/src/dashboard/app/pages/AgentMap.jsx +371 -370
  232. package/src/dashboard/app/pages/FeatureDetail.jsx +604 -0
  233. package/src/dashboard/app/pages/Features.jsx +400 -0
  234. package/src/dashboard/app/pages/Guide.jsx +146 -0
  235. package/src/dashboard/app/pages/HookInspector.jsx +357 -322
  236. package/src/dashboard/app/pages/PhasePipeline.jsx +277 -408
  237. package/src/dashboard/app/pages/Portfolio.jsx +156 -0
  238. package/src/dashboard/app/pages/Rubrics.jsx +101 -0
  239. package/src/dashboard/app/pages/RulesMap.jsx +300 -273
  240. package/src/dashboard/app/pages/SkillsLibrary.jsx +483 -366
  241. package/src/dashboard/app/pages/Standards.jsx +407 -332
  242. package/src/dashboard/app/styles/index.css +187 -47
  243. package/src/dashboard/index.html +14 -12
  244. package/src/dashboard/package.json +32 -24
  245. package/src/dashboard/scanner/activity-scanner.js +351 -0
  246. package/src/dashboard/scanner/agents-scanner.js +63 -1
  247. package/src/dashboard/scanner/docs-scanner.js +59 -0
  248. package/src/dashboard/scanner/feature-status.js +10 -0
  249. package/src/dashboard/scanner/features-scanner.js +360 -0
  250. package/src/dashboard/scanner/hooks-scanner.js +8 -1
  251. package/src/dashboard/scanner/index.js +14 -7
  252. package/src/dashboard/scanner/phases-scanner.js +14 -15
  253. package/src/dashboard/scanner/portfolio.js +153 -0
  254. package/src/dashboard/scanner/project-api.js +195 -0
  255. package/src/dashboard/scanner/rules-scanner.js +42 -37
  256. package/src/dashboard/scanner/skills-scanner.js +105 -43
  257. package/src/dashboard/scanner/standards-scanner.js +4 -1
  258. package/src/dashboard/vite-plugin-morph-data.js +134 -17
  259. package/src/lib/ai/comment-stripper.js +101 -4
  260. package/src/lib/detectors/claude-config-detector.js +2 -7
  261. package/src/lib/detectors/index.js +5 -1
  262. package/src/lib/evaluator-report.js +47 -0
  263. package/src/lib/generators/handoff-generator.js +4 -18
  264. package/src/lib/generators/settings-generator.js +208 -209
  265. package/src/lib/git/default-branch.js +52 -0
  266. package/src/lib/git/tree-fingerprint.js +58 -0
  267. package/src/lib/git/tree-state.js +167 -0
  268. package/src/lib/graph/god-nodes.js +12 -3
  269. package/src/lib/graph/graph-health.js +48 -2
  270. package/src/lib/graph/graph-loader.js +99 -25
  271. package/src/lib/graph/graphifyignore.js +145 -28
  272. package/src/lib/graph/sanitize.js +117 -11
  273. package/src/lib/installers/mcp-installer.js +724 -719
  274. package/src/lib/installers/memory-installer.js +1 -2
  275. package/src/lib/projects/registry.js +154 -0
  276. package/src/lib/risk-detector.js +90 -0
  277. package/src/lib/specs/acervo-format.js +70 -0
  278. package/src/lib/specs/acervo-lifecycle.js +264 -0
  279. package/src/lib/specs/adr-index.js +169 -0
  280. package/src/lib/specs/revocations.js +156 -0
  281. package/src/lib/specs/screen-checklist.js +357 -0
  282. package/src/lib/specs/usecase-check.js +20 -16
  283. package/src/lib/specs/usecase-promoter.js +103 -38
  284. package/src/lib/specs/usecase-registry.js +7 -7
  285. package/src/lib/tasks/tasks-json-parser.js +2 -3
  286. package/src/lib/telemetry/metrics.js +386 -0
  287. package/src/lib/telemetry/telemetry-reader.js +161 -51
  288. package/src/lib/telemetry/verify-event.js +79 -0
  289. package/src/lib/validators/code-budget/code-budget-validator.js +200 -0
  290. package/src/lib/validators/code-budget/comment-scanner.js +75 -0
  291. package/src/lib/validators/code-budget/index.js +9 -0
  292. package/src/lib/validators/reuse/reuse-validator.js +4 -2
  293. package/src/lib/validators/reuse/symbol-scanner.js +27 -22
  294. package/src/lib/validators/validation-runner.js +21 -5
  295. package/src/lib/validators/verify-runner.js +11 -0
  296. package/src/lib/worktree/finish-backup.js +739 -0
  297. package/src/lib/worktree/ignored-triage.js +15 -8
  298. package/src/lib/worktree/worktree-audit.js +5 -0
  299. package/src/scripts/install-plugin.js +1 -1
  300. package/src/scripts/setup-infra.js +31 -22
  301. package/src/utils/agents-installer.js +338 -24
  302. package/src/utils/banner.js +1 -1
  303. package/src/utils/hooks-installer.js +75 -15
  304. package/src/commands/index.js +0 -13
  305. package/src/commands/project/checkpoint.js +0 -209
  306. package/src/core/state/phase-state-machine.js +0 -197
  307. package/src/dashboard/app/hooks/useDetailPanel.js +0 -15
  308. package/src/dashboard/app/pages/LiveState.jsx +0 -206
  309. package/src/dashboard/scanner/squads-scanner.js +0 -13
  310. package/src/dashboard/scanner/state-scanner.js +0 -85
  311. package/src/lib/generators/index.js +0 -10
  312. package/src/lib/hooks/hook-executor.js +0 -167
  313. package/src/lib/validators/checkpoint-persistence.js +0 -39
  314. package/src/lib/validators/shared/emit-validator-dispatch.js +0 -14
  315. package/src/lib/validators/shared/index.js +0 -12
  316. package/src/lib/validators/shared/issue-counter.js +0 -14
  317. package/src/lib/validators/shared/result-formatter.js +0 -124
@@ -4,48 +4,8 @@ using Morph.AiKit.Agents;
4
4
 
5
5
  namespace Morph.AiKit.Observability;
6
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
7
  public static class MorphOpenTelemetryExtensions
38
8
  {
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
9
  public static ChatClientBuilder UseMorphTelemetry(this ChatClientBuilder builder, MorphTelemetryOptions options)
50
10
  {
51
11
  ArgumentNullException.ThrowIfNull(builder);
@@ -59,10 +19,6 @@ public static class MorphOpenTelemetryExtensions
59
19
  : inner);
60
20
  }
61
21
 
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
22
  public static AIAgentBuilder UseMorphTelemetry(this AIAgentBuilder builder, MorphTelemetryOptions options)
67
23
  {
68
24
  ArgumentNullException.ThrowIfNull(builder);
@@ -76,20 +32,6 @@ public static class MorphOpenTelemetryExtensions
76
32
  });
77
33
  }
78
34
 
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
35
  public static AgentFactoryOptions WithMorphTelemetry(
94
36
  this AgentFactoryOptions factoryOptions,
95
37
  MorphTelemetryOptions options)
@@ -109,10 +51,7 @@ public static class MorphOpenTelemetryExtensions
109
51
  ? options with { EnableSensitiveData = sensitive }
110
52
  : options;
111
53
 
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>
54
+ // GetService atravessa a cadeia de delegates (MAF 1.20.0), entao detecta instrumentacao ja aplicada abaixo.
116
55
  private static bool ShouldInstrument(IChatClient inner, MorphTelemetryOptions options)
117
56
  => options.InstrumentChatClient
118
57
  ?? inner.GetService(typeof(OpenTelemetryChatClient)) is null;
@@ -1,31 +1,10 @@
1
1
  namespace Morph.AiKit.Observability;
2
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
3
  public sealed record MorphTelemetryOptions
22
4
  {
23
5
  private readonly string _sourceName = string.Empty;
24
6
 
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>
7
+ // AgentOpenTelemetryConsts e internal no Microsoft.Agents.AI 1.20.0, entao o nome e do projeto.
29
8
  public required string SourceName
30
9
  {
31
10
  get => _sourceName;
@@ -36,47 +15,8 @@ public sealed record MorphTelemetryOptions
36
15
  }
37
16
  }
38
17
 
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
18
  public bool EnableSensitiveData { get; init; }
45
19
 
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>
20
+ // null instrumenta so se o pipeline ainda nao tem OpenTelemetryChatClient; true duplica o span de chat.
81
21
  public bool? InstrumentChatClient { get; init; }
82
22
  }
@@ -2,32 +2,8 @@ using Microsoft.Extensions.AI;
2
2
 
3
3
  namespace Morph.AiKit.Providers;
4
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>
5
+ // O ModelRegistry memoiza e descarta o que a fabrica cria; a fabrica nao guarda cliente.
26
6
  public interface IProviderClientFactory
27
7
  {
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
8
  IChatClient CreateChatClient(ModelAlias alias);
33
9
  }
@@ -3,31 +3,6 @@ using Morph.AiKit.Agents;
3
3
 
4
4
  namespace Morph.AiKit.Providers;
5
5
 
6
- /// <summary>
7
- /// Um alias do <c>model-registry.v2.json</c>: o apelido estavel que os agentes citam, com
8
- /// tudo o que e preciso saber para alcancar o modelo e para contabilizar o que ele custa.
9
- /// </summary>
10
- /// <remarks>
11
- /// <para>
12
- /// Estende a forma de <c>templates/code/dotnet/ai-agents/ModelRegistry.cs.template</c>
13
- /// (provider + model + options) com os dois campos que a issue #92 exige e que o template
14
- /// v1 nao tinha: <see cref="Api"/> — o protocolo, por alias — e a decisao de tarifa
15
- /// (<see cref="Pricing"/> ou <see cref="PricingWaiver"/>).
16
- /// </para>
17
- /// <para>
18
- /// <b>Invariante do tipo:</b> ou existe <see cref="Pricing"/>, ou existe
19
- /// <see cref="PricingWaiver"/> — nunca os dois, nunca nenhum. E o que impede
20
- /// <c>cost_usd</c> de sair nulo la na frente: a ausencia de tarifa passa a ser uma decisao
21
- /// escrita por alguem, com motivo, e nao um campo que ninguem preencheu.
22
- /// <see cref="ValidatePricingDecision"/> e o guardiao dessa invariante e e chamado pelo
23
- /// <see cref="ModelRegistry"/> em toda carga.
24
- /// </para>
25
- /// </remarks>
26
- /// <param name="Provider">Familia de SDK: <c>openai</c>, <c>google</c>, <c>ollama</c>...</param>
27
- /// <param name="Model">Id do modelo no provider.</param>
28
- /// <param name="Api">Protocolo deste alias. Ver <see cref="AgentApi"/>.</param>
29
- /// <param name="Pricing">Tarifa por 1M de tokens, ou nulo se houver <see cref="PricingWaiver"/>.</param>
30
- /// <param name="Endpoint">Endpoint alternativo (Ollama, gateway). Nulo = o padrao do SDK.</param>
31
6
  public sealed record ModelAlias(
32
7
  string Provider,
33
8
  string Model,
@@ -35,35 +10,17 @@ public sealed record ModelAlias(
35
10
  ModelPricing? Pricing,
36
11
  string? Endpoint)
37
12
  {
38
- /// <summary>A chave do alias no documento — <c>text-default</c>, <c>reasoning</c>...</summary>
39
13
  public required string Name { get; init; }
40
14
 
41
- /// <summary>
42
- /// Motivo, por extenso, de este alias nao ter tarifa. Preenchido <b>somente</b> quando
43
- /// <see cref="Pricing"/> e nulo. Exemplo real: modelo local, onde a conta e a maquina e
44
- /// nao o token.
45
- /// </summary>
46
15
  public string? PricingWaiver { get; init; }
47
16
 
48
- /// <summary>Limites conhecidos deste alias. Ver <see cref="ModelAliasConstraints"/>.</summary>
49
17
  public ModelAliasConstraints Constraints { get; init; } = ModelAliasConstraints.None;
50
18
 
51
- /// <summary>Se ha tarifa. Quando falso, <see cref="PricingWaiver"/> explica por que.</summary>
52
19
  public bool HasPricing => Pricing is not null;
53
20
 
54
- /// <summary>
55
- /// A tarifa, ou uma falha que diz o nome do alias e o motivo declarado da ausencia.
56
- /// Use quando o custo e obrigatorio; use <see cref="HasPricing"/> quando ausencia de
57
- /// tarifa e um caminho previsto (e o caso do <c>UsageCostMiddleware</c>, que registra
58
- /// tokens com custo zero e sinaliza a ausencia — nunca inventa tarifa).
59
- /// </summary>
60
21
  public ModelPricing RequirePricing()
61
22
  => Pricing ?? throw ModelRegistryException.MissingPricing(Name, PricingWaiver);
62
23
 
63
- /// <summary>
64
- /// Cobra a invariante "tarifa OU dispensa, nunca ambas, nunca nenhuma".
65
- /// </summary>
66
- /// <exception cref="ModelRegistryException">Quando a decisao de tarifa nao foi tomada.</exception>
67
24
  public static void ValidatePricingDecision(ModelAlias alias)
68
25
  {
69
26
  ArgumentNullException.ThrowIfNull(alias);
@@ -87,21 +44,6 @@ public sealed record ModelAlias(
87
44
  }
88
45
  }
89
46
 
90
- /// <summary>
91
- /// Confronta uma requisicao com os limites declarados deste alias, <b>sem lancar</b> —
92
- /// a decisao de abortar, avisar ou seguir e de quem chama (a <c>AgentFactory</c>).
93
- /// </summary>
94
- /// <param name="effectiveApi">
95
- /// O protocolo que vai valer de fato: <c>spec.Api ?? alias.Api</c>. Veja
96
- /// <see cref="AgentSpec.ResolveApi"/> — a precedencia mora la, nao aqui.
97
- /// </param>
98
- /// <param name="hasTools">Se a requisicao leva tools.</param>
99
- /// <param name="reasoningEffort">
100
- /// O esforco que sera enviado, ou nulo quando nada sera enviado. <b>Nulo nao e
101
- /// violacao</b>: nesse caso vale o default do provider, e qual e ele o kit nao afirma
102
- /// saber — modelar o contrario seria trocar um fato por folclore.
103
- /// </param>
104
- /// <param name="temperatureIsSet">Se a requisicao envia temperatura.</param>
105
47
  public AliasRequestCheck CheckRequest(
106
48
  AgentApi effectiveApi,
107
49
  bool hasTools,
@@ -135,38 +77,13 @@ public sealed record ModelAlias(
135
77
  }
136
78
  }
137
79
 
138
- /// <summary>
139
- /// Tarifa de um alias, em USD por 1 milhao de tokens. Vive junto do alias porque a conta
140
- /// so faz sentido com a tarifa daquele modelo — e porque a matematica do custo, escrita
141
- /// uma vez aqui, nao pode divergir entre o middleware (T11) e um relatorio qualquer.
142
- /// </summary>
143
- /// <param name="InputPerMTok">USD por 1M de tokens de entrada.</param>
144
- /// <param name="OutputPerMTok">USD por 1M de tokens de saida.</param>
145
- /// <param name="CachedInputPerMTok">
146
- /// USD por 1M de tokens de entrada servidos do cache do provider. Nulo = <b>nao ha desconto
147
- /// declarado</b>, e entao token cacheado e cobrado como entrada normal. Nulo NUNCA significa
148
- /// "de graca": inventar desconto e tao errado quanto inventar tarifa.
149
- /// </param>
150
80
  public sealed record ModelPricing(
151
81
  decimal InputPerMTok,
152
82
  decimal OutputPerMTok,
153
83
  decimal? CachedInputPerMTok)
154
84
  {
155
- /// <summary>Tokens a que a tarifa se refere: 1 milhao.</summary>
156
85
  public const decimal TokensPerTariffUnit = 1_000_000m;
157
86
 
158
- /// <summary>
159
- /// Custo em USD de uma volta, a partir das contagens de token da resposta.
160
- /// </summary>
161
- /// <remarks>
162
- /// <paramref name="cachedInputTokens"/> e um <b>subconjunto</b> de
163
- /// <paramref name="inputTokens"/> — e assim que o provider reporta e assim que
164
- /// <c>UsageDetails.CachedInputTokenCount</c> espelha. A parte cacheada so e cobrada a
165
- /// parte quando <see cref="CachedInputPerMTok"/> existe; sem tarifa de cache, toda a
166
- /// entrada e cobrada pela tarifa de entrada.
167
- /// </remarks>
168
- /// <exception cref="ArgumentOutOfRangeException">Contagem negativa.</exception>
169
- /// <exception cref="ArgumentException">Tokens cacheados maiores que os de entrada.</exception>
170
87
  public decimal ComputeCostUsd(long inputTokens, long outputTokens, long? cachedInputTokens = null)
171
88
  {
172
89
  ArgumentOutOfRangeException.ThrowIfNegative(inputTokens);
@@ -196,52 +113,18 @@ public sealed record ModelPricing(
196
113
  }
197
114
  }
198
115
 
199
- /// <summary>
200
- /// Limites conhecidos de um alias. <b>Por alias, com procedencia escrita</b> — nunca uma
201
- /// regra universal chumbada no codigo.
202
- /// </summary>
203
- /// <remarks>
204
- /// A diferenca importa: "modelo de raciocinio rejeita tool" e folclore; o que a
205
- /// documentacao diz e mais estreito e cabe num campo. Um limite sem
206
- /// <see cref="Provenance"/> e recusado na carga do registry, justamente para que ninguem
207
- /// consiga gravar um "todo mundo sabe que" sem dizer de onde tirou.
208
- /// </remarks>
209
116
  public sealed record ModelAliasConstraints
210
117
  {
211
- /// <summary>Nenhum limite declarado.</summary>
212
118
  public static readonly ModelAliasConstraints None = new();
213
119
 
214
- /// <summary>
215
- /// Na <b>Chat Completions</b>, este modelo so aceita tool calling com reasoning effort
216
- /// <c>none</c>. E o limite exato descrito pela documentacao — mais estreito que
217
- /// "modelo de raciocinio nao aceita tool" — e por isso e verificado com os quatro fatos
218
- /// juntos em <see cref="ModelAlias.CheckRequest"/>: protocolo Chat, tools presentes,
219
- /// effort enviado, e effort diferente de <c>none</c>.
220
- /// </summary>
221
120
  public bool ToolCallingRequiresReasoningEffortNone { get; init; }
222
121
 
223
- /// <summary>
224
- /// Este modelo nao aceita <c>temperature</c>.
225
- /// <b>Existe como flag por alias exatamente porque a afirmacao generica
226
- /// ("temperatura e obsoleta para modelos de raciocinio") NAO foi confirmada em fonte
227
- /// primaria.</b> Quem ligar isto assume a afirmacao para um modelo especifico e escreve
228
- /// de onde tirou em <see cref="Provenance"/>.
229
- /// </summary>
230
122
  public bool TemperatureUnsupported { get; init; }
231
123
 
232
- /// <summary>
233
- /// De onde veio o limite: documento, data, citacao. Obrigatorio quando qualquer flag
234
- /// esta ligada.
235
- /// </summary>
236
124
  public string? Provenance { get; init; }
237
125
 
238
- /// <summary>Se ha qualquer limite declarado.</summary>
239
126
  public bool AnyFlagSet => ToolCallingRequiresReasoningEffortNone || TemperatureUnsupported;
240
127
 
241
- /// <summary>
242
- /// Cobra "limite ligado exige procedencia".
243
- /// </summary>
244
- /// <exception cref="ModelRegistryException">Flag ligada sem procedencia.</exception>
245
128
  public void ValidateProvenance(string aliasName)
246
129
  {
247
130
  if (AnyFlagSet && string.IsNullOrWhiteSpace(Provenance))
@@ -254,14 +137,7 @@ public sealed record ModelAliasConstraints
254
137
  }
255
138
  }
256
139
 
257
- /// <summary>
258
- /// Resultado de <see cref="ModelAlias.CheckRequest"/>. Result, nao excecao: um limite
259
- /// violado e informacao para quem chama decidir, nao fluxo de controle.
260
- /// </summary>
261
- /// <param name="IsSatisfied">Se a requisicao respeita todos os limites do alias.</param>
262
- /// <param name="Violations">Uma frase por limite violado, ja com a procedencia.</param>
263
140
  public sealed record AliasRequestCheck(bool IsSatisfied, IReadOnlyList<string> Violations)
264
141
  {
265
- /// <summary>Nenhuma violacao.</summary>
266
142
  public static readonly AliasRequestCheck Satisfied = new(true, []);
267
143
  }
@@ -4,28 +4,6 @@ using Morph.AiKit.Agents;
4
4
 
5
5
  namespace Morph.AiKit.Providers;
6
6
 
7
- /// <summary>
8
- /// Fonte unica de "que modelo e esse apelido": le o documento
9
- /// <c>model-registry.v2.json</c>, resolve alias e memoiza um <see cref="IChatClient"/> por
10
- /// alias.
11
- /// </summary>
12
- /// <remarks>
13
- /// <para>
14
- /// Estende a forma de <c>templates/code/dotnet/ai-agents/ModelRegistry.cs.template</c> —
15
- /// documento JSON como fonte unica, cache de cliente por alias — e acrescenta as duas
16
- /// coisas que a issue #92 cobra: <b><c>api:</c> por alias</b> e <b>tarifa por alias</b>.
17
- /// A construcao do cliente saiu de dentro da classe e virou
18
- /// <see cref="IProviderClientFactory"/>: e essa mudanca que torna o kit testavel em CI sem
19
- /// rede e sem chave de API.
20
- /// </para>
21
- /// <para>
22
- /// <b>Toda falha aqui e falha de carga, nao fluxo de controle.</b> Documento invalido,
23
- /// alias sem decisao de tarifa, limite sem procedencia: tudo estoura em
24
- /// <see cref="FromJson"/>, na composicao, com o nome do alias e o motivo — nunca vira um
25
- /// nulo que atravessa tres camadas e aparece como custo zerado num relatorio. Para o
26
- /// caminho quente ha <see cref="TryResolve"/>, que nao lanca.
27
- /// </para>
28
- /// </remarks>
29
7
  public sealed class ModelRegistry : IDisposable
30
8
  {
31
9
  private const string SupportedDocumentVersion = "2.0";
@@ -48,6 +26,7 @@ public sealed class ModelRegistry : IDisposable
48
26
  };
49
27
 
50
28
  private readonly Dictionary<string, ModelAlias> _aliases;
29
+ // Um cliente por alias: cliente de provider carrega pool de conexao, e recria-lo por chamada vaza socket.
51
30
  private readonly Dictionary<string, IChatClient> _clients = new(StringComparer.Ordinal);
52
31
  private readonly IProviderClientFactory _factory;
53
32
  private readonly Lock _gate = new();
@@ -63,21 +42,10 @@ public sealed class ModelRegistry : IDisposable
63
42
  DefaultAlias = defaultAlias;
64
43
  }
65
44
 
66
- /// <summary>Alias usado quando quem chama nao escolhe um. Nulo se o documento nao declara.</summary>
67
45
  public string? DefaultAlias { get; }
68
46
 
69
- /// <summary>Os aliases do documento, na ordem em que foram declarados.</summary>
70
47
  public IReadOnlyCollection<string> Aliases => _aliases.Keys;
71
48
 
72
- /// <summary>
73
- /// Le o documento e valida tudo o que pode ser validado antes de a primeira requisicao
74
- /// existir.
75
- /// </summary>
76
- /// <exception cref="ModelRegistryException">
77
- /// JSON invalido, campo obrigatorio faltando, <c>api</c> desconhecida, chave nao
78
- /// reconhecida, tarifa negativa, alias sem decisao de tarifa, ou limite sem procedencia.
79
- /// A mensagem sempre nomeia o alias e o campo.
80
- /// </exception>
81
49
  public static ModelRegistry FromJson(string json, IProviderClientFactory factory)
82
50
  {
83
51
  ArgumentException.ThrowIfNullOrWhiteSpace(json);
@@ -155,12 +123,6 @@ public sealed class ModelRegistry : IDisposable
155
123
  }
156
124
  }
157
125
 
158
- /// <summary>
159
- /// O alias, ou falha nomeando os aliases que existem.
160
- /// <b>Nunca devolve nulo</b> — alias desconhecido e erro de configuracao, e um nulo
161
- /// silencioso aqui vira um <c>NullReferenceException</c> em outro arquivo.
162
- /// </summary>
163
- /// <exception cref="ModelRegistryException">Alias desconhecido.</exception>
164
126
  public ModelAlias Resolve(string alias)
165
127
  {
166
128
  ArgumentException.ThrowIfNullOrWhiteSpace(alias);
@@ -170,7 +132,6 @@ public sealed class ModelRegistry : IDisposable
170
132
  : throw ModelRegistryException.UnknownAlias(alias, _aliases.Keys);
171
133
  }
172
134
 
173
- /// <summary>Versao sem excecao de <see cref="Resolve"/>, para caminho quente.</summary>
174
135
  public bool TryResolve(string alias, out ModelAlias? resolved)
175
136
  {
176
137
  ArgumentException.ThrowIfNullOrWhiteSpace(alias);
@@ -178,14 +139,6 @@ public sealed class ModelRegistry : IDisposable
178
139
  return _aliases.TryGetValue(alias, out resolved);
179
140
  }
180
141
 
181
- /// <summary>
182
- /// O <see cref="IChatClient"/> do alias, <b>memoizado</b>: a fabrica e chamada uma unica
183
- /// vez por alias, e as chamadas seguintes devolvem a mesma instancia. Cliente de provider
184
- /// carrega pool de conexao e handler; recria-lo por chamada e como o vazamento de socket
185
- /// costuma nascer.
186
- /// </summary>
187
- /// <exception cref="ModelRegistryException">Alias desconhecido, ou fabrica devolvendo nulo.</exception>
188
- /// <exception cref="ObjectDisposedException">O registry ja foi descartado.</exception>
189
142
  public IChatClient GetChatClient(string alias)
190
143
  {
191
144
  var resolved = Resolve(alias);
@@ -209,10 +162,6 @@ public sealed class ModelRegistry : IDisposable
209
162
  }
210
163
  }
211
164
 
212
- /// <summary>
213
- /// Descarta os clientes memoizados. O registry e dono do que a fabrica criou — ver a
214
- /// nota de ownership em <see cref="IProviderClientFactory"/>.
215
- /// </summary>
216
165
  public void Dispose()
217
166
  {
218
167
  List<IChatClient> toDispose;
@@ -261,8 +210,6 @@ public sealed class ModelRegistry : IDisposable
261
210
  Constraints = ReadConstraints(name, element),
262
211
  };
263
212
 
264
- // As duas invariantes que fazem este registry valer a pena: a decisao de tarifa e
265
- // explicita, e todo limite declarado diz de onde veio.
266
213
  ModelAlias.ValidatePricingDecision(alias);
267
214
  alias.Constraints.ValidateProvenance(name);
268
215
 
@@ -273,8 +220,6 @@ public sealed class ModelRegistry : IDisposable
273
220
  {
274
221
  if (!element.TryGetProperty("api", out var api))
275
222
  {
276
- // Omitir 'api' e cair na Responses API — a decisao da casa. Chat Completions
277
- // exige alguem escrever "chat", ou seja, exige assumir a escolha.
278
223
  return AgentApi.Responses;
279
224
  }
280
225
 
@@ -284,9 +229,6 @@ public sealed class ModelRegistry : IDisposable
284
229
  {
285
230
  "responses" => AgentApi.Responses,
286
231
  "chat" => AgentApi.Chat,
287
- // Midia entra no MESMO registry: um vocabulario so de alias, um lugar so onde
288
- // se pergunta "que modelos este projeto usa". Um alias assim nao vira agente —
289
- // a AgentFactory o recusa com erro nomeado.
290
232
  "images" => AgentApi.Images,
291
233
  "videos" => AgentApi.Videos,
292
234
  _ => throw ModelRegistryException.InvalidDocument(
@@ -416,55 +358,41 @@ public sealed class ModelRegistry : IDisposable
416
358
  }
417
359
  }
418
360
 
419
- /// <summary>Motivo de uma falha do <see cref="ModelRegistry"/>. Discrimina sem exigir hierarquia de excecao.</summary>
420
361
  public enum ModelRegistryError
421
362
  {
422
- /// <summary>Documento invalido: JSON quebrado, campo faltando, valor fora do contrato.</summary>
423
363
  InvalidDocument = 0,
424
364
 
425
- /// <summary>Alias inexistente no documento carregado.</summary>
426
365
  UnknownAlias = 1,
427
366
 
428
- /// <summary>Alias sem tarifa, com o motivo da ausencia declarado no <c>pricingWaiver</c>.</summary>
429
367
  MissingPricing = 2,
430
368
  }
431
369
 
432
- /// <summary>
433
- /// Falha de configuracao do registry. <c>sealed</c> com um <see cref="Reason"/> em vez de
434
- /// uma arvore de subclasses: quem trata precisa discriminar o motivo, nao herdar dele.
435
- /// </summary>
436
370
  public sealed class ModelRegistryException : InvalidOperationException
437
371
  {
438
372
  private ModelRegistryException(ModelRegistryError reason, string message, Exception? inner = null)
439
373
  : base(message, inner)
440
374
  => Reason = reason;
441
375
 
442
- /// <summary>Cria a excecao sem motivo especifico. Prefira as fabricas nomeadas.</summary>
443
376
  public ModelRegistryException(string message)
444
377
  : this(ModelRegistryError.InvalidDocument, message)
445
378
  {
446
379
  }
447
380
 
448
- /// <summary>Cria a excecao encadeando a causa.</summary>
449
381
  public ModelRegistryException(string message, Exception innerException)
450
382
  : this(ModelRegistryError.InvalidDocument, message, innerException)
451
383
  {
452
384
  }
453
385
 
454
- /// <summary>Por que falhou.</summary>
455
386
  public ModelRegistryError Reason { get; }
456
387
 
457
- /// <summary>Documento fora do contrato.</summary>
458
388
  public static ModelRegistryException InvalidDocument(string message, Exception? inner = null)
459
389
  => new(ModelRegistryError.InvalidDocument, message, inner);
460
390
 
461
- /// <summary>Alias desconhecido — a mensagem lista os que existem.</summary>
462
391
  public static ModelRegistryException UnknownAlias(string alias, IEnumerable<string> known)
463
392
  => new(
464
393
  ModelRegistryError.UnknownAlias,
465
394
  $"alias desconhecido: '{alias}'. Declarados no model-registry: {string.Join(", ", known)}.");
466
395
 
467
- /// <summary>Tarifa exigida de um alias que declarou dispensa.</summary>
468
396
  public static ModelRegistryException MissingPricing(string alias, string? waiver)
469
397
  => new(
470
398
  ModelRegistryError.MissingPricing,