@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.
- package/CLAUDE.md +20 -3
- package/README.md +2 -2
- package/bin/morph-spec.js +18 -4
- package/bin/validate.js +379 -379
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +5 -4
- package/docs/QUICKSTART.md +1 -1
- package/framework/MORPH.md +16 -17
- package/framework/agents.json +197 -44
- package/framework/ai-pin.json +22 -0
- package/framework/commands/morph-media.md +45 -0
- package/framework/docs/CLI.md +234 -9
- package/framework/evals/proof-rubrics/README.md +76 -0
- package/framework/evals/proof-rubrics/eval-de-modelo.md +64 -0
- package/framework/evals/proof-rubrics/fiacao.md +54 -0
- package/framework/evals/proof-rubrics/guard-cego.md +52 -0
- package/framework/evals/proof-rubrics/media-claims.md +109 -0
- package/framework/evals/proof-rubrics/mutation-proof.md +77 -0
- package/framework/evals/proof-rubrics/observabilidade-genai.md +119 -0
- package/framework/evals/proof-rubrics/verde-nao-e-coberto.md +48 -0
- package/framework/evals/rubrics/architecture.md +30 -0
- package/framework/evals/rubrics/code-quality.md +26 -0
- package/framework/evals/rubrics/test-coverage.md +20 -0
- package/framework/hooks/claude-code/core/protect-spec-files.js +41 -4
- package/framework/hooks/claude-code/statusline.sh +11 -11
- package/framework/hooks/git/commit-msg/conventional-commits.sh +33 -33
- package/framework/hooks/git/pre-commit/agents.sh +25 -25
- package/framework/hooks/git/pre-commit/orchestrator.sh +64 -64
- package/framework/hooks/git/pre-commit/specs.sh +50 -50
- package/framework/hooks/git/pre-push/run-tests.sh +44 -44
- package/framework/hooks/shared/e2e-check.js +135 -22
- package/framework/hooks/shared/stdin-reader.js +26 -26
- package/framework/rules/ai-agents-standards.md +14 -2
- package/framework/schemas/ai-pin.schema.json +97 -0
- package/framework/schemas/config.schema.json +107 -0
- package/framework/schemas/feature.schema.json +23 -4
- package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
- package/framework/skills/core/morph-apply/SKILL.md +26 -5
- package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
- package/framework/skills/core/morph-eval/SKILL.md +1 -1
- package/framework/skills/core/morph-hotfix/SKILL.md +2 -2
- package/framework/skills/core/morph-implement/SKILL.md +18 -2
- package/framework/skills/core/morph-media/SKILL.md +215 -0
- package/framework/skills/core/morph-plan/SKILL.md +33 -2
- package/framework/skills/core/morph-proposal/SKILL.md +1 -1
- package/framework/skills/core/morph-review/SKILL.md +166 -9
- package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
- package/framework/skills/core/morph-standards/SKILL.md +1 -1
- package/framework/skills/core/morph-uiux/SKILL.md +1 -1
- package/framework/standards/PROVENANCE.json +81 -3
- package/framework/standards/STANDARDS.json +1483 -839
- package/framework/standards/ai-agents/agent-archetypes.md +160 -0
- package/framework/standards/ai-agents/agent-session.md +164 -68
- package/framework/standards/ai-agents/agent-spec.md +196 -0
- package/framework/standards/ai-agents/batching.md +61 -37
- package/framework/standards/ai-agents/context-providers.md +97 -24
- package/framework/standards/ai-agents/conversational-agent-with-phases.md +239 -0
- package/framework/standards/ai-agents/cost-and-budget.md +256 -0
- package/framework/standards/ai-agents/durable-workflows-hitl.md +98 -5
- package/framework/standards/ai-agents/evals-with-cache.md +289 -0
- package/framework/standards/ai-agents/guardrails.md +222 -0
- package/framework/standards/ai-agents/llm-runtime-defaults.md +226 -0
- package/framework/standards/ai-agents/mcp-server.md +119 -18
- package/framework/standards/ai-agents/mcp-tools.md +85 -32
- package/framework/standards/ai-agents/media-pipeline.md +352 -0
- package/framework/standards/ai-agents/media-video.md +267 -0
- package/framework/standards/ai-agents/middleware-patterns.md +39 -5
- package/framework/standards/ai-agents/modalities-image-gen.md +354 -105
- package/framework/standards/ai-agents/modalities-speech-to-text.md +8 -2
- package/framework/standards/ai-agents/modalities-text-to-speech.md +10 -2
- package/framework/standards/ai-agents/modalities-vision.md +6 -2
- package/framework/standards/ai-agents/multi-agent-patterns.md +61 -5
- package/framework/standards/ai-agents/observability-patterns.md +227 -17
- package/framework/standards/ai-agents/production.md +38 -9
- package/framework/standards/ai-agents/prompt-sources.md +389 -0
- package/framework/standards/ai-agents/providers/model-registry.md +174 -39
- package/framework/standards/ai-agents/rag-custom-pgvector.md +69 -4
- package/framework/standards/ai-agents/service-tier-flex.md +27 -19
- package/framework/standards/ai-agents/setup.md +166 -50
- package/framework/standards/ai-agents/structured-output.md +34 -3
- package/framework/standards/ai-agents/sweet-spot.md +23 -3
- package/framework/standards/ai-agents/testing-ai.md +236 -0
- package/framework/standards/ai-agents/vector-data-extensions.md +50 -20
- package/framework/standards/ai-agents/workflows.md +27 -7
- package/framework/standards/frontend/design-system/ai-image-generation.md +12 -0
- package/framework/standards/frontend/design-system/ai-video-generation.md +13 -0
- package/framework/standards/infrastructure/docker/local-compose-isolation.md +3 -1
- package/framework/templates/.idea/morph-templates.xml +92 -0
- package/framework/templates/.vscode/morph-templates.code-snippets +186 -0
- package/framework/templates/IDE-SNIPPETS.md +262 -262
- package/framework/templates/REGISTRY.json +13 -0
- package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
- package/framework/templates/code/dotnet/ai-agents/AgentBootstrap.cs.template +39 -39
- package/framework/templates/code/dotnet/ai-agents/EmbeddingService.cs.template +68 -68
- package/framework/templates/code/dotnet/ai-agents/ModelRegistry.cs.template +117 -117
- package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +1 -1
- package/framework/templates/code/dotnet/ai-agents/ResilientToolMiddleware.cs.template +61 -61
- package/framework/templates/code/dotnet/ai-agents/VectorSearchTool.cs.template +107 -107
- package/framework/templates/code/dotnet/ai-agents/model-registry.json.template +58 -58
- package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +281 -281
- package/framework/templates/code/dotnet/database/migration.cs +83 -83
- package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +21 -21
- package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -4
- package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -4
- package/framework/templates/code/dotnet/feature/validator.cs.hbs +15 -15
- package/framework/templates/code/sql/ai-agents/agent-prompts-migration.sql.template +1 -1
- package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -91
- package/framework/templates/code/typescript/contracts.ts +167 -167
- package/framework/templates/docs/clarifications.md +253 -253
- package/framework/templates/docs/schema-analysis.md +119 -119
- package/framework/templates/docs/ui-components.md +52 -52
- package/framework/templates/docs/ui-design-system.md +76 -76
- package/framework/templates/docs/ui-flows.md +167 -167
- package/framework/templates/docs/ui-mockups.md +98 -98
- package/framework/templates/dotnet/ai-kit/Directory.Build.props +25 -0
- package/framework/templates/dotnet/ai-kit/Directory.Packages.props +26 -0
- package/framework/templates/dotnet/ai-kit/Morph.AiKit.sln +56 -0
- package/framework/templates/dotnet/ai-kit/NuGet.config +12 -0
- package/framework/templates/dotnet/ai-kit/README.md +128 -0
- package/framework/templates/dotnet/ai-kit/global.json +9 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentApi.cs +65 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactory.cs +289 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactoryOptions.cs +91 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpec.cs +91 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpecOptions.cs +181 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/AiKitAssemblyMarker.cs +14 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/ConversationStore.cs +174 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/IConversationStore.cs +54 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/InMemoryConversationStore.cs +75 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/CountingChatClient.cs +71 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalAssertion.cs +246 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheMissException.cs +57 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheOptions.cs +78 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheStamp.cs +225 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalFixture.cs +463 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalMode.cs +32 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalQualityEvaluators.cs +49 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalScenario.cs +214 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalSummary.cs +168 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/OfflineChatClient.cs +142 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/ShortPathResponseCache.cs +349 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaGenerator.cs +42 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaProvider.cs +77 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaArtifact.cs +28 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaDisclosure.cs +107 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaGenerator.cs +253 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaIdempotencyKey.cs +103 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJob.cs +259 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobId.cs +21 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobState.cs +47 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaPricing.cs +102 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaProvenance.cs +44 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaRequest.cs +192 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaResult.cs +94 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaReview.cs +99 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaSeams.cs +97 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaStore.cs +133 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MorphMedia.cs +93 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/GoogleImageProvider.cs +112 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/OpenAIImageProvider.cs +288 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/VeoVideoProvider.cs +158 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/IUsageCostSink.cs +29 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostMiddleware.cs +208 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostRecord.cs +95 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Morph.AiKit.csproj +38 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphOpenTelemetryExtensions.cs +119 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphTelemetryOptions.cs +82 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/IProviderClientFactory.cs +33 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelAlias.cs +267 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelRegistry.cs +474 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/model-registry.v2.json +87 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs +169 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaPlan.cs +49 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentFactoryTests.cs +495 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentSpecTests.cs +260 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ConversationStoreTests.cs +405 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/DeltaIngestTests.cs +379 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalAssertionTests.cs +197 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheMissTests.cs +139 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheStampTests.cs +157 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFailuresTests.cs +178 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFixtureTests.cs +153 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalRefreshTests.cs +194 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalWorkspace.cs +86 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/KitEvals.cs +213 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/OfflineChatClientTests.cs +95 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClient.cs +225 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClientTests.cs +215 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeClock.cs +33 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeMediaProvider.cs +89 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeProviderClientFactory.cs +55 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeUsageCostSink.cs +60 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/InMemoryMediaStore.cs +131 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAccessibilityTests.cs +133 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAliasIsNotAnAgentTests.cs +127 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +216 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaGeneratorTests.cs +264 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaIdempotencyKeyTests.cs +148 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaJobStateTests.cs +184 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaReviewTests.cs +89 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaStoreTests.cs +98 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ModelRegistryTests.cs +451 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Morph.AiKit.Tests.csproj +76 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/SkeletonSmokeTests.cs +33 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/TelemetryTests.cs +261 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/UsageCostMiddlewareTests.cs +374 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/.morph-eval-cache.json +12 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/orcamento/acme/a-resposta-estruturada.json +24 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/a-saudacao.json +23 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/b-escalonamento.json +24 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/globex/a-saudacao.json +23 -0
- package/framework/templates/feature/decisions.md +122 -122
- package/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +43 -43
- package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
- package/framework/templates/frontend/nextjs/env.mjs.hbs +32 -32
- package/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -56
- package/framework/templates/frontend/nextjs/page.tsx.hbs +22 -22
- package/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -26
- package/framework/templates/frontend/nextjs/use-feature.ts.hbs +54 -54
- package/framework/templates/infrastructure/docker/Dockerfile.template +58 -58
- package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
- package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
- package/framework/templates/infrastructure/github/README.md +56 -56
- package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -45
- package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -27
- package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -59
- package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -39
- package/framework/templates/integrations/asaas-client.cs +387 -387
- package/framework/templates/integrations/asaas-webhook.cs +351 -351
- package/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -76
- package/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -100
- package/framework/templates/meta-prompts/validators/pre-commit-validator.md +95 -95
- package/framework/templates/project/validate.js +120 -120
- package/framework/templates/state.template.json +17 -17
- package/framework/templates/ui/design-system.css +226 -226
- package/package.json +3 -3
- package/src/commands/dashboard/dashboard.js +53 -53
- package/src/commands/e2e/e2e.js +15 -2
- package/src/commands/index.js +13 -13
- package/src/commands/project/checkpoint.js +209 -209
- package/src/commands/project/doctor.js +140 -5
- package/src/commands/project/update.js +469 -153
- package/src/commands/project/worktree.js +8 -1
- package/src/commands/state/advance.js +24 -2
- package/src/commands/state/approve.js +33 -1
- package/src/commands/state/create.js +72 -11
- package/src/commands/state/finish.js +333 -21
- package/src/commands/state/gate-check.js +190 -6
- package/src/commands/state/score.js +36 -1
- package/src/commands/validation/verify.js +134 -25
- package/src/core/state/phase-state-machine.js +197 -197
- package/src/core/state/state-manager.js +9 -1
- package/src/core/templates/template-renderer.js +477 -477
- package/src/dashboard/app/components/DetailPanel.jsx +11 -11
- package/src/dashboard/app/components/FlowGraph.jsx +17 -17
- package/src/dashboard/app/components/SearchFilter.jsx +22 -22
- package/src/dashboard/app/hooks/useDetailPanel.js +15 -15
- package/src/dashboard/app/main.jsx +13 -13
- package/src/dashboard/app/pages/AgentMap.jsx +370 -370
- package/src/dashboard/app/pages/PhasePipeline.jsx +408 -408
- package/src/dashboard/app/pages/RulesMap.jsx +273 -273
- package/src/dashboard/app/pages/SkillsLibrary.jsx +366 -366
- package/src/dashboard/app/pages/Standards.jsx +332 -332
- package/src/dashboard/app/styles/index.css +47 -47
- package/src/dashboard/index.html +12 -12
- package/src/dashboard/package.json +24 -24
- package/src/dashboard/scanner/phases-scanner.js +15 -15
- package/src/dashboard/scanner/rubrics-scanner.js +12 -12
- package/src/dashboard/scanner/rules-scanner.js +37 -37
- package/src/dashboard/scanner/skills-scanner.js +43 -43
- package/src/dashboard/scanner/squads-scanner.js +13 -13
- package/src/dashboard/vite-plugin-morph-data.js +17 -17
- package/src/dashboard/vite.config.js +24 -24
- package/src/lib/ai/ai-checks.js +182 -0
- package/src/lib/ai/ai-project-scan.js +347 -0
- package/src/lib/ai/code-audit.js +181 -0
- package/src/lib/ai/comment-stripper.js +184 -0
- package/src/lib/ai/pin-drift.js +138 -0
- package/src/lib/ai/registry-audit.js +285 -0
- package/src/lib/detectors/design-system-detector.js +188 -188
- package/src/lib/detectors/index.js +217 -217
- package/src/lib/e2e/compose-env.js +50 -4
- package/src/lib/evaluator-report.js +269 -15
- package/src/lib/generators/design-system-generator.js +508 -508
- package/src/lib/generators/settings-generator.js +209 -209
- package/src/lib/git/default-branch.js +92 -4
- package/src/lib/hooks/hook-executor.js +167 -167
- package/src/lib/installers/effects.js +193 -0
- package/src/lib/installers/mcp-installer.js +719 -719
- package/src/lib/installers/templates-reconcile.js +3 -3
- package/src/lib/risk-detector.js +284 -0
- package/src/lib/standards/verified-against.js +276 -0
- package/src/lib/tasks/eval-node.js +485 -0
- package/src/lib/tasks/linux-runner.js +297 -0
- package/src/lib/tasks/task-classifier.js +30 -30
- package/src/lib/tasks/task-parser.js +209 -209
- package/src/lib/tasks/test-nodes.js +486 -0
- package/src/lib/tasks/test-runner.js +410 -33
- package/src/lib/validators/checkpoint-persistence.js +39 -39
- package/src/lib/validators/css/css-validator.js +340 -340
- package/src/lib/validators/shared/emit-validator-dispatch.js +14 -14
- package/src/lib/validators/shared/issue-counter.js +14 -14
- package/src/lib/validators/verify-runner.js +583 -28
- package/src/lib/worktree/docker-audit.js +287 -0
- package/src/lib/worktree/env-allocator.js +24 -0
- package/src/lib/worktree/worktree-audit.js +30 -1
- package/src/scripts/setup-infra.js +24 -11
- package/src/utils/agent-id-mapper.js +11 -11
- package/src/utils/agents-installer.js +18 -8
- package/src/utils/claude-md-injector.js +10 -5
- package/src/utils/claude-settings-manager.js +300 -300
- package/src/utils/file-copier.js +11 -4
- package/src/utils/hooks-installer.js +29 -26
- package/src/utils/skills-installer.js +36 -29
- package/src/utils/version-checker.js +68 -3
- package/framework/standards/ai-agents/prompts-in-db.md +0 -214
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
using System.Runtime.CompilerServices;
|
|
2
|
+
using Microsoft.Extensions.AI;
|
|
3
|
+
using Morph.AiKit.Providers;
|
|
4
|
+
|
|
5
|
+
namespace Morph.AiKit.Middleware;
|
|
6
|
+
|
|
7
|
+
/// <summary>
|
|
8
|
+
/// Middleware de <see cref="IChatClient"/> que le o <c>Usage</c> da resposta, aplica a
|
|
9
|
+
/// tarifa do alias e publica uma linha de custo em <see cref="IUsageCostSink"/>.
|
|
10
|
+
/// </summary>
|
|
11
|
+
/// <remarks>
|
|
12
|
+
/// <para>
|
|
13
|
+
/// <b>Onde ele entra no pipeline:</b> <b>ACIMA</b> da invocacao de funcoes, com a
|
|
14
|
+
/// telemetria de chat abaixo dela (<c>usage-cost -> function-invocation ->
|
|
15
|
+
/// OpenTelemetry -> cliente do provider</c>). Na pratica: a
|
|
16
|
+
/// <c>AgentFactory.BuildChatPipeline</c> registra o encaixe de custo <b>antes</b> de
|
|
17
|
+
/// <c>UseFunctionInvocation</c>, e no <c>ChatClientBuilder</c> o primeiro registrado e o
|
|
18
|
+
/// mais <b>externo</b>. A ordem nao e estetica, e o motivo e o
|
|
19
|
+
/// <c>FunctionInvokingChatClient</c> (FICC): acima dele o middleware ve <b>uma</b> resposta
|
|
20
|
+
/// cujo <c>Usage</c> ja vem com o total de todas as voltas de tool (medido: duas voltas de
|
|
21
|
+
/// 10/4 e 30/6 chegam como <c>in=40, out=10</c>) e publica <b>uma</b> linha por chamada.
|
|
22
|
+
/// Abaixo dele veria as respostas parciais — e leria o mesmo objeto <c>UsageDetails</c> que
|
|
23
|
+
/// o proprio FICC <b>muta</b> para acumular, o que faria a mesma conta dar resultado
|
|
24
|
+
/// diferente conforme a hora de ler. Isso e medido, nao argumentado, em
|
|
25
|
+
/// <c>AgentFactoryTests.ThePipelineOrderIsUsageCostAboveFunctionInvocationAndTelemetryBelowIt</c>
|
|
26
|
+
/// (sequencia <c>usage-cost:enter -> telemetry:enter/exit x2 -> usage-cost:exit</c>) e
|
|
27
|
+
/// em <c>AgentFactoryTests.UsageCostAboveFunctionInvocationSeesTheUsageOfEveryToolRoundSummedOnce</c>.
|
|
28
|
+
/// A montagem do pipeline e da <c>AgentFactory</c> (T10); daqui so depende a extensao
|
|
29
|
+
/// <see cref="UsageCostChatClientBuilderExtensions.UseUsageCost"/>.
|
|
30
|
+
/// </para>
|
|
31
|
+
/// <para>
|
|
32
|
+
/// <b>Nota de errata:</b> o <c>spec.md</c> sec. 3.1 desta feature prescrevia a seta
|
|
33
|
+
/// literal <c>function-invocation -> usage-cost -> OpenTelemetry</c>, que se le ao
|
|
34
|
+
/// contrario do que esta implementado aqui. A divergencia foi medida na T10 sec. 3.2 e esta
|
|
35
|
+
/// registrada como <b>Errata E9</b> no proprio <c>spec.md</c> — o corpo do plano e
|
|
36
|
+
/// append-only e continua com a seta antiga; a verdade e esta.
|
|
37
|
+
/// </para>
|
|
38
|
+
/// <para>
|
|
39
|
+
/// <b>A conta e a do <see cref="ModelPricing.ComputeCostUsd"/>, nao uma segunda.</b> Este
|
|
40
|
+
/// tipo nao contem aritmetica de tarifa: ele converte <c>Usage</c> em argumentos, chama a
|
|
41
|
+
/// conta que ja existe e carimba o resultado. Reescrever a formula aqui daria dois numeros
|
|
42
|
+
/// para o mesmo custo — que e literalmente a dor no nome desta epica (em ProspectPRO a
|
|
43
|
+
/// conta esta repetida em cinco agentes).
|
|
44
|
+
/// </para>
|
|
45
|
+
/// <para>
|
|
46
|
+
/// <b>Nunca lanca por causa de tarifa.</b> Alias sem tarifa e caminho previsto: sai
|
|
47
|
+
/// <c>CostUsd = 0</c> com <see cref="UsageCostStatus.Waived"/> e o motivo escrito no
|
|
48
|
+
/// record. Inventar tarifa e pior que nao ter. E resposta sem <c>Usage</c> sai como
|
|
49
|
+
/// <see cref="UsageCostStatus.UsageMissing"/> — visivel, em vez de silenciosa.
|
|
50
|
+
/// </para>
|
|
51
|
+
/// </remarks>
|
|
52
|
+
public sealed class UsageCostMiddleware : DelegatingChatClient
|
|
53
|
+
{
|
|
54
|
+
private readonly ModelAlias _alias;
|
|
55
|
+
private readonly IUsageCostSink _sink;
|
|
56
|
+
private readonly TimeProvider _timeProvider;
|
|
57
|
+
|
|
58
|
+
/// <summary>Monta o middleware sobre um cliente interno.</summary>
|
|
59
|
+
/// <param name="innerClient">O proximo elo do pipeline.</param>
|
|
60
|
+
/// <param name="alias">
|
|
61
|
+
/// O alias que atende este cliente — de onde vem a tarifa e o nome que vai no record.
|
|
62
|
+
/// </param>
|
|
63
|
+
/// <param name="sink">Para onde as linhas de custo vao.</param>
|
|
64
|
+
/// <param name="timeProvider">
|
|
65
|
+
/// Relogio. Nulo usa <see cref="TimeProvider.System"/>. Injetavel porque o standard
|
|
66
|
+
/// <c>backend-dotnet-testing</c> proibe <c>DateTimeOffset.UtcNow</c> direto num tipo
|
|
67
|
+
/// testavel — sem isso, o instante do record e intestavel.
|
|
68
|
+
/// </param>
|
|
69
|
+
public UsageCostMiddleware(
|
|
70
|
+
IChatClient innerClient,
|
|
71
|
+
ModelAlias alias,
|
|
72
|
+
IUsageCostSink sink,
|
|
73
|
+
TimeProvider? timeProvider = null)
|
|
74
|
+
: base(innerClient)
|
|
75
|
+
{
|
|
76
|
+
ArgumentNullException.ThrowIfNull(alias);
|
|
77
|
+
ArgumentNullException.ThrowIfNull(sink);
|
|
78
|
+
|
|
79
|
+
_alias = alias;
|
|
80
|
+
_sink = sink;
|
|
81
|
+
_timeProvider = timeProvider ?? TimeProvider.System;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/// <inheritdoc />
|
|
85
|
+
public override async Task<ChatResponse> GetResponseAsync(
|
|
86
|
+
IEnumerable<ChatMessage> messages,
|
|
87
|
+
ChatOptions? options = null,
|
|
88
|
+
CancellationToken cancellationToken = default)
|
|
89
|
+
{
|
|
90
|
+
var response = await base.GetResponseAsync(messages, options, cancellationToken)
|
|
91
|
+
.ConfigureAwait(false);
|
|
92
|
+
|
|
93
|
+
Publish(response.Usage);
|
|
94
|
+
|
|
95
|
+
return response;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/// <inheritdoc />
|
|
99
|
+
/// <remarks>
|
|
100
|
+
/// No streaming o <c>Usage</c> chega como <see cref="UsageContent"/> avulso, tipicamente
|
|
101
|
+
/// no ultimo update — e pode chegar em mais de um pedaco. Os pedacos sao somados e a
|
|
102
|
+
/// linha de custo sai <b>uma unica vez</b>, ao fim da enumeracao: emitir por update daria
|
|
103
|
+
/// N linhas para uma volta so.
|
|
104
|
+
/// </remarks>
|
|
105
|
+
public override async IAsyncEnumerable<ChatResponseUpdate> GetStreamingResponseAsync(
|
|
106
|
+
IEnumerable<ChatMessage> messages,
|
|
107
|
+
ChatOptions? options = null,
|
|
108
|
+
[EnumeratorCancellation] CancellationToken cancellationToken = default)
|
|
109
|
+
{
|
|
110
|
+
UsageDetails? accumulated = null;
|
|
111
|
+
|
|
112
|
+
await foreach (var update in base.GetStreamingResponseAsync(messages, options, cancellationToken)
|
|
113
|
+
.ConfigureAwait(false))
|
|
114
|
+
{
|
|
115
|
+
foreach (var content in update.Contents)
|
|
116
|
+
{
|
|
117
|
+
if (content is UsageContent usage)
|
|
118
|
+
{
|
|
119
|
+
(accumulated ??= new UsageDetails()).Add(usage.Details);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
yield return update;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
Publish(accumulated);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private void Publish(UsageDetails? usage)
|
|
130
|
+
{
|
|
131
|
+
var at = _timeProvider.GetUtcNow();
|
|
132
|
+
|
|
133
|
+
if (usage is null || (usage.InputTokenCount is null && usage.OutputTokenCount is null))
|
|
134
|
+
{
|
|
135
|
+
// Sem relato de uso nao ha o que tarifar. A linha sai assim mesmo, marcada: um
|
|
136
|
+
// custo que ninguem consegue medir precisa aparecer, nao sumir.
|
|
137
|
+
_sink.Record(new UsageCostRecord(_alias.Name, 0, 0, null, 0m, at)
|
|
138
|
+
{
|
|
139
|
+
Status = UsageCostStatus.UsageMissing,
|
|
140
|
+
});
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
var input = usage.InputTokenCount ?? 0L;
|
|
145
|
+
var output = usage.OutputTokenCount ?? 0L;
|
|
146
|
+
var cached = usage.CachedInputTokenCount;
|
|
147
|
+
|
|
148
|
+
if (_alias.Pricing is not { } pricing)
|
|
149
|
+
{
|
|
150
|
+
// Caminho previsto, nunca excecao: o alias declarou por escrito que nao tem
|
|
151
|
+
// tarifa (o registry recusa a carga de um alias sem tarifa E sem dispensa).
|
|
152
|
+
_sink.Record(new UsageCostRecord(_alias.Name, input, output, cached, 0m, at)
|
|
153
|
+
{
|
|
154
|
+
Status = UsageCostStatus.Waived,
|
|
155
|
+
PricingWaiver = _alias.PricingWaiver,
|
|
156
|
+
});
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Um provider que reporte 'cached' maior que 'input' esta se contradizendo; a conta
|
|
161
|
+
// do T8 recusa esse par. Aqui o dado inconsistente vira lacuna declarada, e nao uma
|
|
162
|
+
// excecao que derruba a resposta do usuario por causa de um contador.
|
|
163
|
+
if (cached > input)
|
|
164
|
+
{
|
|
165
|
+
_sink.Record(new UsageCostRecord(_alias.Name, input, output, cached, 0m, at)
|
|
166
|
+
{
|
|
167
|
+
Status = UsageCostStatus.UsageMissing,
|
|
168
|
+
});
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
_sink.Record(new UsageCostRecord(
|
|
173
|
+
_alias.Name,
|
|
174
|
+
input,
|
|
175
|
+
output,
|
|
176
|
+
cached,
|
|
177
|
+
pricing.ComputeCostUsd(input, output, cached),
|
|
178
|
+
at)
|
|
179
|
+
{
|
|
180
|
+
Status = UsageCostStatus.Computed,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/// <summary>
|
|
186
|
+
/// Registro do <see cref="UsageCostMiddleware"/> no pipeline de <see cref="IChatClient"/>.
|
|
187
|
+
/// </summary>
|
|
188
|
+
public static class UsageCostChatClientBuilderExtensions
|
|
189
|
+
{
|
|
190
|
+
/// <summary>
|
|
191
|
+
/// Insere a contabilizacao de custo no pipeline, com a tarifa do alias dado.
|
|
192
|
+
/// </summary>
|
|
193
|
+
/// <param name="builder">O builder do pipeline.</param>
|
|
194
|
+
/// <param name="alias">Alias que atende este cliente.</param>
|
|
195
|
+
/// <param name="sink">Destino das linhas de custo.</param>
|
|
196
|
+
/// <param name="timeProvider">Relogio; nulo usa <see cref="TimeProvider.System"/>.</param>
|
|
197
|
+
/// <returns>O proprio builder, para encadear.</returns>
|
|
198
|
+
public static ChatClientBuilder UseUsageCost(
|
|
199
|
+
this ChatClientBuilder builder,
|
|
200
|
+
ModelAlias alias,
|
|
201
|
+
IUsageCostSink sink,
|
|
202
|
+
TimeProvider? timeProvider = null)
|
|
203
|
+
{
|
|
204
|
+
ArgumentNullException.ThrowIfNull(builder);
|
|
205
|
+
|
|
206
|
+
return builder.Use(inner => new UsageCostMiddleware(inner, alias, sink, timeProvider));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
using Morph.AiKit.Providers;
|
|
2
|
+
|
|
3
|
+
namespace Morph.AiKit.Middleware;
|
|
4
|
+
|
|
5
|
+
/// <summary>
|
|
6
|
+
/// Como o custo de uma volta ao modelo ficou conhecido. Existe para que
|
|
7
|
+
/// <see cref="UsageCostRecord.CostUsd"/> possa ser um <see cref="decimal"/> nao-anulavel
|
|
8
|
+
/// <b>sem que zero passe a significar tres coisas diferentes</b>.
|
|
9
|
+
/// </summary>
|
|
10
|
+
/// <remarks>
|
|
11
|
+
/// A dor que esta feature nomeia e <c>cost_usd</c> saindo nulo. Trocar o nulo por um zero
|
|
12
|
+
/// mudo seria trocar um defeito por outro pior — zero soma, nulo nao. Aqui o valor e sempre
|
|
13
|
+
/// um numero e o status diz se aquele numero e uma medicao, uma decisao ou uma lacuna.
|
|
14
|
+
/// </remarks>
|
|
15
|
+
public enum UsageCostStatus
|
|
16
|
+
{
|
|
17
|
+
/// <summary>
|
|
18
|
+
/// Tarifa do alias aplicada sobre uso reportado pelo provider. O unico status em que
|
|
19
|
+
/// <see cref="UsageCostRecord.CostUsd"/> e uma <b>medicao</b> — e o unico que pode
|
|
20
|
+
/// entrar numa soma de fatura sem ressalva.
|
|
21
|
+
/// </summary>
|
|
22
|
+
Computed = 0,
|
|
23
|
+
|
|
24
|
+
/// <summary>
|
|
25
|
+
/// O alias nao tem tarifa e <b>tem dispensa escrita</b>
|
|
26
|
+
/// (<c>ModelAlias.PricingWaiver</c>). Custo zero por decisao registrada — modelo local,
|
|
27
|
+
/// por exemplo, onde a conta e a maquina e nao o token. O motivo viaja em
|
|
28
|
+
/// <see cref="UsageCostRecord.PricingWaiver"/>: um zero aqui nunca e anonimo.
|
|
29
|
+
/// </summary>
|
|
30
|
+
Waived = 1,
|
|
31
|
+
|
|
32
|
+
/// <summary>
|
|
33
|
+
/// O provider <b>nao reportou</b> <c>Usage</c> nesta volta. Os tokens sao desconhecidos,
|
|
34
|
+
/// logo o custo tambem e: o zero em <see cref="UsageCostRecord.CostUsd"/> e ausencia de
|
|
35
|
+
/// medicao, <b>nao</b> gratuidade. Some com <see cref="Computed"/> apenas ciente disso.
|
|
36
|
+
/// </summary>
|
|
37
|
+
UsageMissing = 2,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/// <summary>
|
|
41
|
+
/// O custo de uma volta ao modelo, ja calculado. <b>Uma linha por resposta</b>, pronta para
|
|
42
|
+
/// virar registro de banco, metrica ou linha de fatura.
|
|
43
|
+
/// </summary>
|
|
44
|
+
/// <remarks>
|
|
45
|
+
/// <para>
|
|
46
|
+
/// <b><see cref="CostUsd"/> nunca e nulo — por construcao do tipo.</b> Esse e o ponto
|
|
47
|
+
/// inteiro: a dor catalogada na issue e um <c>cost_usd</c> nulo atravessando tres camadas
|
|
48
|
+
/// e aparecendo como buraco no relatorio. A ausencia de tarifa deixou de poder chegar ate
|
|
49
|
+
/// aqui por esquecimento: o <c>ModelRegistry</c> (T8) <b>recusa a carga</b> de um alias que
|
|
50
|
+
/// nao declare <c>pricing</c> nem <c>pricingWaiver</c>. Logo, quando este record sai com
|
|
51
|
+
/// <see cref="UsageCostStatus.Waived"/>, existe necessariamente um motivo escrito em
|
|
52
|
+
/// <see cref="PricingWaiver"/>.
|
|
53
|
+
/// </para>
|
|
54
|
+
/// <para>
|
|
55
|
+
/// <b>A conta nao mora aqui.</b> Ela mora em <see cref="ModelPricing.ComputeCostUsd"/>
|
|
56
|
+
/// (T8), e o <see cref="UsageCostMiddleware"/> apenas a chama. Uma segunda aritmetica do
|
|
57
|
+
/// mesmo custo e o defeito que esta epica tem no nome: em ProspectPRO ela esta repetida
|
|
58
|
+
/// literalmente em cinco agentes, e duas copias da mesma conta divergem — a divergencia
|
|
59
|
+
/// aparece na fatura.
|
|
60
|
+
/// </para>
|
|
61
|
+
/// </remarks>
|
|
62
|
+
/// <param name="Alias">O alias do <c>ModelRegistry</c> que atendeu a volta.</param>
|
|
63
|
+
/// <param name="InputTokens">Tokens de entrada reportados. Zero quando nao houve relato.</param>
|
|
64
|
+
/// <param name="OutputTokens">Tokens de saida reportados. Zero quando nao houve relato.</param>
|
|
65
|
+
/// <param name="CachedInputTokens">
|
|
66
|
+
/// Tokens de entrada servidos do cache do provider, ou nulo quando o provider nao reporta.
|
|
67
|
+
/// E <b>subconjunto</b> de <paramref name="InputTokens"/>, nunca uma parcela a mais.
|
|
68
|
+
/// </param>
|
|
69
|
+
/// <param name="CostUsd">
|
|
70
|
+
/// Custo em USD. Nunca nulo; leia <see cref="Status"/> antes de somar.
|
|
71
|
+
/// </param>
|
|
72
|
+
/// <param name="At">Instante da volta, vindo do <see cref="TimeProvider"/> injetado.</param>
|
|
73
|
+
public sealed record UsageCostRecord(
|
|
74
|
+
string Alias,
|
|
75
|
+
long InputTokens,
|
|
76
|
+
long OutputTokens,
|
|
77
|
+
long? CachedInputTokens,
|
|
78
|
+
decimal CostUsd,
|
|
79
|
+
DateTimeOffset At)
|
|
80
|
+
{
|
|
81
|
+
/// <summary>Como o custo ficou conhecido. Ver <see cref="UsageCostStatus"/>.</summary>
|
|
82
|
+
public required UsageCostStatus Status { get; init; }
|
|
83
|
+
|
|
84
|
+
/// <summary>
|
|
85
|
+
/// O motivo escrito de o alias nao ter tarifa, copiado de
|
|
86
|
+
/// <c>ModelAlias.PricingWaiver</c>. Preenchido <b>somente</b> com
|
|
87
|
+
/// <see cref="UsageCostStatus.Waived"/>.
|
|
88
|
+
/// </summary>
|
|
89
|
+
public string? PricingWaiver { get; init; }
|
|
90
|
+
|
|
91
|
+
/// <summary>
|
|
92
|
+
/// Se <see cref="CostUsd"/> e uma medicao — o unico caso em que somar e honesto.
|
|
93
|
+
/// </summary>
|
|
94
|
+
public bool IsMeasuredCost => Status == UsageCostStatus.Computed;
|
|
95
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
|
2
|
+
|
|
3
|
+
<PropertyGroup>
|
|
4
|
+
<RootNamespace>Morph.AiKit</RootNamespace>
|
|
5
|
+
<AssemblyName>Morph.AiKit</AssemblyName>
|
|
6
|
+
</PropertyGroup>
|
|
7
|
+
|
|
8
|
+
<!--
|
|
9
|
+
A REGRA DURA DE ai-agents/media-pipeline.md, presa por acessibilidade.
|
|
10
|
+
|
|
11
|
+
Morph.AiKit.Media.IMediaProvider e os tres adaptadores de provider sao `internal`: um
|
|
12
|
+
handler do projeto consumidor NAO consegue nomear o tipo que produz bytes, e o codigo
|
|
13
|
+
nao compila. A unica superficie publica e IMediaGenerator.EnqueueAsync, que devolve um
|
|
14
|
+
id de job.
|
|
15
|
+
|
|
16
|
+
Esta linha e a UNICA excecao, e ela existe para que a suite possa asserir a
|
|
17
|
+
acessibilidade por reflexao e exercitar o worker com um provider fake. Acrescentar um
|
|
18
|
+
segundo InternalsVisibleTo aqui — para o projeto consumidor, "so para testar" — desfaz
|
|
19
|
+
o mecanismo inteiro; o teste MediaAccessibilityTests grita se os tipos virarem publicos,
|
|
20
|
+
mas nao consegue ver quem mais foi convidado para dentro.
|
|
21
|
+
-->
|
|
22
|
+
<ItemGroup>
|
|
23
|
+
<InternalsVisibleTo Include="Morph.AiKit.Tests" />
|
|
24
|
+
</ItemGroup>
|
|
25
|
+
|
|
26
|
+
<!-- Sem atributo Version: as versoes vem de Directory.Packages.props (gerado do pin). -->
|
|
27
|
+
<ItemGroup>
|
|
28
|
+
<PackageReference Include="Microsoft.Agents.AI" />
|
|
29
|
+
<PackageReference Include="Microsoft.Extensions.AI" />
|
|
30
|
+
<PackageReference Include="OpenAI" />
|
|
31
|
+
<PackageReference Include="Google.GenAI" />
|
|
32
|
+
<PackageReference Include="ModelContextProtocol" />
|
|
33
|
+
<PackageReference Include="Microsoft.Extensions.AI.Evaluation" />
|
|
34
|
+
<PackageReference Include="Microsoft.Extensions.AI.Evaluation.Quality" />
|
|
35
|
+
<PackageReference Include="Microsoft.Extensions.AI.Evaluation.Reporting" />
|
|
36
|
+
</ItemGroup>
|
|
37
|
+
|
|
38
|
+
</Project>
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
using Microsoft.Agents.AI;
|
|
2
|
+
using Microsoft.Extensions.AI;
|
|
3
|
+
using Morph.AiKit.Agents;
|
|
4
|
+
|
|
5
|
+
namespace Morph.AiKit.Observability;
|
|
6
|
+
|
|
7
|
+
/// <summary>
|
|
8
|
+
/// Liga as GenAI semantic conventions nos dois niveis do kit — agente e chat client — com
|
|
9
|
+
/// <b>um guard contra span duplicado em cada um</b>.
|
|
10
|
+
/// </summary>
|
|
11
|
+
/// <remarks>
|
|
12
|
+
/// <para>
|
|
13
|
+
/// <b>O que foi medido no pin (Microsoft.Agents.AI 1.20.0), e nao suposto:</b>
|
|
14
|
+
/// </para>
|
|
15
|
+
/// <list type="bullet">
|
|
16
|
+
/// <item>
|
|
17
|
+
/// Uma invocacao instrumentada produz <c>invoke_agent</c> (raiz) e <c>chat</c> (filho).
|
|
18
|
+
/// Duas camadas de instrumentacao no MESMO nivel produzem o span daquele nivel duas
|
|
19
|
+
/// vezes: dois <c>OpenTelemetryChatClient</c> dao dois <c>chat</c>; dois
|
|
20
|
+
/// <c>OpenTelemetryAgent</c> dao dois <c>invoke_agent</c>.
|
|
21
|
+
/// </item>
|
|
22
|
+
/// <item>
|
|
23
|
+
/// <c>GetService</c> atravessa a cadeia de delegates nos dois niveis — e por isso que
|
|
24
|
+
/// "ja existe instrumentacao aqui embaixo?" e uma pergunta respondivel, e nao um
|
|
25
|
+
/// palpite. E o predicado dos dois guards.
|
|
26
|
+
/// </item>
|
|
27
|
+
/// <item>
|
|
28
|
+
/// O MAF 1.20.0 tem um guard proprio, mas ele so alcanca o pipeline que o
|
|
29
|
+
/// <c>ChatClientAgent</c> monta sozinho. A <c>AgentFactory</c> monta o proprio
|
|
30
|
+
/// (<c>UseProvidedChatClientAsIs = true</c>) para poder posicionar o custo e ajustar o
|
|
31
|
+
/// tool calling — e nesse arranjo o slot do MAF nao existe. Medido: agente
|
|
32
|
+
/// instrumentado + pipeline proprio sem estas extensoes = <b>zero</b> spans de chat.
|
|
33
|
+
/// O guard daqui nao duplica o do MAF; ele cobre o pipeline que o MAF nao ve.
|
|
34
|
+
/// </item>
|
|
35
|
+
/// </list>
|
|
36
|
+
/// </remarks>
|
|
37
|
+
public static class MorphOpenTelemetryExtensions
|
|
38
|
+
{
|
|
39
|
+
/// <summary>
|
|
40
|
+
/// Instrumenta o pipeline de chat. Aplicado pela <c>AgentFactory</c> ABAIXO do
|
|
41
|
+
/// <c>FunctionInvokingChatClient</c>, que e onde o MAF 1.20.0 documenta que a
|
|
42
|
+
/// instrumentacao tem de ficar para o span de chat fechar antes das tools.
|
|
43
|
+
/// </summary>
|
|
44
|
+
/// <remarks>
|
|
45
|
+
/// O guard vive na decisao de <see cref="ShouldInstrument"/>: com
|
|
46
|
+
/// <see cref="MorphTelemetryOptions.InstrumentChatClient"/> nulo (o default), um
|
|
47
|
+
/// pipeline que ja carrega um <see cref="OpenTelemetryChatClient"/> e devolvido intacto.
|
|
48
|
+
/// </remarks>
|
|
49
|
+
public static ChatClientBuilder UseMorphTelemetry(this ChatClientBuilder builder, MorphTelemetryOptions options)
|
|
50
|
+
{
|
|
51
|
+
ArgumentNullException.ThrowIfNull(builder);
|
|
52
|
+
ArgumentNullException.ThrowIfNull(options);
|
|
53
|
+
|
|
54
|
+
return builder.Use(inner => ShouldInstrument(inner, options)
|
|
55
|
+
? new OpenTelemetryChatClient(inner, logger: null, sourceName: options.SourceName)
|
|
56
|
+
{
|
|
57
|
+
EnableSensitiveData = options.EnableSensitiveData,
|
|
58
|
+
}
|
|
59
|
+
: inner);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/// <summary>
|
|
63
|
+
/// Instrumenta o agente — o span <c>invoke_agent</c>, o mais externo, que cobre a
|
|
64
|
+
/// invocacao inteira. Um agente que ja e instrumentado e devolvido intacto.
|
|
65
|
+
/// </summary>
|
|
66
|
+
public static AIAgentBuilder UseMorphTelemetry(this AIAgentBuilder builder, MorphTelemetryOptions options)
|
|
67
|
+
{
|
|
68
|
+
ArgumentNullException.ThrowIfNull(builder);
|
|
69
|
+
ArgumentNullException.ThrowIfNull(options);
|
|
70
|
+
|
|
71
|
+
return builder.Use(inner => inner.GetService(typeof(OpenTelemetryAgent)) is not null
|
|
72
|
+
? inner
|
|
73
|
+
: new OpenTelemetryAgent(inner, options.SourceName)
|
|
74
|
+
{
|
|
75
|
+
EnableSensitiveData = options.EnableSensitiveData,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/// <summary>
|
|
80
|
+
/// Preenche os dois encaixes de telemetria da <see cref="AgentFactoryOptions"/> de uma
|
|
81
|
+
/// vez, respeitando <see cref="AgentSpecOptions.EnableSensitiveTelemetry"/> quando a
|
|
82
|
+
/// spec opinou.
|
|
83
|
+
/// </summary>
|
|
84
|
+
/// <remarks>
|
|
85
|
+
/// A fabrica e dona da POSICAO de cada encaixe; esta extensao so diz o que ocupa cada
|
|
86
|
+
/// um. E por aqui que a T10 e a T12 se encontram sem uma referenciar a outra.
|
|
87
|
+
/// <para>
|
|
88
|
+
/// <c>EnableSensitiveTelemetry</c> nulo na spec significa "nao opinei" e mantem o valor
|
|
89
|
+
/// destas opcoes; <c>false</c> significa "decidi que nao" e vence. A diferenca entre os
|
|
90
|
+
/// dois e preservada de proposito desde a T7.
|
|
91
|
+
/// </para>
|
|
92
|
+
/// </remarks>
|
|
93
|
+
public static AgentFactoryOptions WithMorphTelemetry(
|
|
94
|
+
this AgentFactoryOptions factoryOptions,
|
|
95
|
+
MorphTelemetryOptions options)
|
|
96
|
+
{
|
|
97
|
+
ArgumentNullException.ThrowIfNull(factoryOptions);
|
|
98
|
+
ArgumentNullException.ThrowIfNull(options);
|
|
99
|
+
|
|
100
|
+
return factoryOptions with
|
|
101
|
+
{
|
|
102
|
+
ConfigureChatTelemetry = (builder, spec, _) => builder.UseMorphTelemetry(ForSpec(options, spec)),
|
|
103
|
+
ConfigureAgentTelemetry = (builder, spec, _) => builder.UseMorphTelemetry(ForSpec(options, spec)),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private static MorphTelemetryOptions ForSpec(MorphTelemetryOptions options, AgentSpec spec)
|
|
108
|
+
=> spec.Options.EnableSensitiveTelemetry is { } sensitive
|
|
109
|
+
? options with { EnableSensitiveData = sensitive }
|
|
110
|
+
: options;
|
|
111
|
+
|
|
112
|
+
/// <summary>
|
|
113
|
+
/// <b>O guard.</b> Nulo = instrumenta so o que ainda nao esta instrumentado;
|
|
114
|
+
/// <c>true</c> = instrumenta sempre (e duplica, quando ja havia); <c>false</c> = nunca.
|
|
115
|
+
/// </summary>
|
|
116
|
+
private static bool ShouldInstrument(IChatClient inner, MorphTelemetryOptions options)
|
|
117
|
+
=> options.InstrumentChatClient
|
|
118
|
+
?? inner.GetService(typeof(OpenTelemetryChatClient)) is null;
|
|
119
|
+
}
|
package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphTelemetryOptions.cs
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
namespace Morph.AiKit.Observability;
|
|
2
|
+
|
|
3
|
+
/// <summary>
|
|
4
|
+
/// O que o kit precisa saber para emitir telemetria GenAI: sob que <c>ActivitySource</c>,
|
|
5
|
+
/// com ou sem conteudo sensivel, e — a decisao que este tipo existe para carregar — se a
|
|
6
|
+
/// instrumentacao do chat client deve ser aplicada.
|
|
7
|
+
/// </summary>
|
|
8
|
+
/// <remarks>
|
|
9
|
+
/// <para>
|
|
10
|
+
/// <b>Por que <see cref="SourceName"/> e obrigatorio.</b> O standard
|
|
11
|
+
/// <c>ai-agents-observability-patterns</c> manda usar
|
|
12
|
+
/// <c>AgentOpenTelemetryConsts.DefaultSourceName</c>. No <c>Microsoft.Agents.AI</c> 1.20.0
|
|
13
|
+
/// esse tipo <b>nao e publico</b> (apurado por reflexao sobre o assembly do pin: a classe
|
|
14
|
+
/// se chama <c>OpenTelemetryConsts</c> e e <c>internal</c>). Um kit que quisesse "usar a
|
|
15
|
+
/// constante do MAF" so poderia repetir o texto dela — e um literal copiado envelhece em
|
|
16
|
+
/// silencio na primeira vez que o pacote o mudar. Entao o nome e do projeto: e a MESMA
|
|
17
|
+
/// string que ele passa para <c>AddSource(...)</c> na configuracao do OpenTelemetry, e o
|
|
18
|
+
/// span do agente e o span de chat nascem sob ela, juntos.
|
|
19
|
+
/// </para>
|
|
20
|
+
/// </remarks>
|
|
21
|
+
public sealed record MorphTelemetryOptions
|
|
22
|
+
{
|
|
23
|
+
private readonly string _sourceName = string.Empty;
|
|
24
|
+
|
|
25
|
+
/// <summary>
|
|
26
|
+
/// Nome do <c>ActivitySource</c> dos spans deste kit. Branco e rejeitado na construcao:
|
|
27
|
+
/// um source sem nome e telemetria que ninguem consegue registrar nem coletar.
|
|
28
|
+
/// </summary>
|
|
29
|
+
public required string SourceName
|
|
30
|
+
{
|
|
31
|
+
get => _sourceName;
|
|
32
|
+
init
|
|
33
|
+
{
|
|
34
|
+
ArgumentException.ThrowIfNullOrWhiteSpace(value, nameof(SourceName));
|
|
35
|
+
_sourceName = value;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/// <summary>
|
|
40
|
+
/// Se prompt, resposta, argumentos e resultados de tool entram nos spans. <c>false</c>
|
|
41
|
+
/// por padrao — e o standard exige <c>false</c> fora de dev/staging, porque esse
|
|
42
|
+
/// conteudo e PII do cliente.
|
|
43
|
+
/// </summary>
|
|
44
|
+
public bool EnableSensitiveData { get; init; }
|
|
45
|
+
|
|
46
|
+
/// <summary>
|
|
47
|
+
/// Se o pipeline de chat deve receber instrumentacao propria. <b>Tres valores, e o
|
|
48
|
+
/// default e o guard.</b>
|
|
49
|
+
/// </summary>
|
|
50
|
+
/// <remarks>
|
|
51
|
+
/// <list type="table">
|
|
52
|
+
/// <listheader><term>Valor</term><description>O que faz</description></listheader>
|
|
53
|
+
/// <item>
|
|
54
|
+
/// <term><c>null</c> (default)</term>
|
|
55
|
+
/// <description>
|
|
56
|
+
/// <b>Instrumenta somente se ainda nao houver instrumentacao no pipeline.</b> A
|
|
57
|
+
/// deteccao e <c>GetService(typeof(OpenTelemetryChatClient))</c>, que atravessa a
|
|
58
|
+
/// cadeia de delegates (medido). E este ramo, e so ele, que impede o span de chat
|
|
59
|
+
/// duplicado.
|
|
60
|
+
/// </description>
|
|
61
|
+
/// </item>
|
|
62
|
+
/// <item>
|
|
63
|
+
/// <term><c>true</c></term>
|
|
64
|
+
/// <description>
|
|
65
|
+
/// Instrumenta sempre. Sobre um pipeline ja instrumentado, produz <b>dois</b>
|
|
66
|
+
/// spans <c>chat</c> por invocacao — medido, e pinado por teste. Existe para
|
|
67
|
+
/// documentar o risco, nao para ser ligado.
|
|
68
|
+
/// </description>
|
|
69
|
+
/// </item>
|
|
70
|
+
/// <item>
|
|
71
|
+
/// <term><c>false</c></term>
|
|
72
|
+
/// <description>
|
|
73
|
+
/// Nunca instrumenta. Com a <c>AgentFactory</c>, que monta o proprio pipeline
|
|
74
|
+
/// (<c>UseProvidedChatClientAsIs = true</c>), isso significa <b>nenhum</b> span de
|
|
75
|
+
/// <c>chat</c>: o slot que o MAF reservaria e ativaria sozinho nao existe nesse
|
|
76
|
+
/// arranjo. Escolha consciente, nao default.
|
|
77
|
+
/// </description>
|
|
78
|
+
/// </item>
|
|
79
|
+
/// </list>
|
|
80
|
+
/// </remarks>
|
|
81
|
+
public bool? InstrumentChatClient { get; init; }
|
|
82
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
using Microsoft.Extensions.AI;
|
|
2
|
+
|
|
3
|
+
namespace Morph.AiKit.Providers;
|
|
4
|
+
|
|
5
|
+
/// <summary>
|
|
6
|
+
/// Constroi o <see cref="IChatClient"/> de um alias. E <b>a</b> costura do kit: o unico
|
|
7
|
+
/// ponto em que o codigo toca um provider de verdade.
|
|
8
|
+
/// </summary>
|
|
9
|
+
/// <remarks>
|
|
10
|
+
/// <para>
|
|
11
|
+
/// O <see cref="ModelRegistry"/> nao sabe construir cliente de provider nenhum — de
|
|
12
|
+
/// proposito. Quem sabe e uma implementacao desta interface, e e por isso que a suite do
|
|
13
|
+
/// kit roda sem rede e sem chave de API: em teste, a fabrica devolve
|
|
14
|
+
/// <c>FakeChatClient</c>. Num projeto, ela e o <c>switch</c> por
|
|
15
|
+
/// <see cref="ModelAlias.Provider"/> descrito no standard
|
|
16
|
+
/// <c>ai-agents-providers-model-registry</c> (<c>openai</c> e <c>ollama</c> de saida,
|
|
17
|
+
/// os demais como branch nova).
|
|
18
|
+
/// </para>
|
|
19
|
+
/// <para>
|
|
20
|
+
/// <b>Quem descarta o cliente:</b> o <see cref="ModelRegistry"/>. A fabrica cria; o
|
|
21
|
+
/// registry memoiza por alias e descarta no proprio <c>Dispose</c>. Uma fabrica que
|
|
22
|
+
/// guardasse e reaproveitasse clientes por fora criaria uma segunda cache, e duas caches
|
|
23
|
+
/// da mesma coisa e como um cliente vazado sobrevive a um teste.
|
|
24
|
+
/// </para>
|
|
25
|
+
/// </remarks>
|
|
26
|
+
public interface IProviderClientFactory
|
|
27
|
+
{
|
|
28
|
+
/// <summary>
|
|
29
|
+
/// Cria o cliente do alias dado. Chamado <b>uma vez por alias</b> pelo
|
|
30
|
+
/// <see cref="ModelRegistry"/>; o resultado e memoizado.
|
|
31
|
+
/// </summary>
|
|
32
|
+
IChatClient CreateChatClient(ModelAlias alias);
|
|
33
|
+
}
|