@polymorphism-tech/morph-spec 8.34.2 → 8.35.1
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 +22 -5
- 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 +236 -11
- 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/core/worktree-env-inject.js +43 -0
- 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/payload-utils.js +15 -2
- 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 +148 -6
- package/src/commands/project/update.js +469 -153
- package/src/commands/project/worktree.js +76 -4
- 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 +379 -24
- 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/git/pr-files.js +56 -0
- 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
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
> **Scope:** stacks=["dotnet"]
|
|
4
4
|
> **Layer:** 1 (on-keyword)
|
|
5
|
-
> **Keywords:** multi-agent, agent as tool, agent composition, sequential agents, handoff, sub-agent, agent orchestration
|
|
5
|
+
> **Keywords:** multi-agent, agent as tool, agent composition, sequential agents, handoff, sub-agent, agent orchestration, agente auxiliar, nesting
|
|
6
6
|
> **Read by Claude in:** plan (quando ai-agents-sweet-spot indica multi-agent) + implement
|
|
7
7
|
|
|
8
|
-
**Verified against:**
|
|
8
|
+
**Verified against:** Microsoft.Agents.AI 1.20.0 (ai-pin 2026-09-08) + Microsoft.Agents.AI.Workflows 1.20.0 (**fora do pin**; versão apurada no nuget.org em 2026-09-08). **Verificação documental**, sem cláusula `provado por` — o ai-kit não compõe agentes. As assinaturas de `AgentWorkflowBuilder`/`HandoffWorkflowBuilder` e a **ausência** do atributo `[Experimental]` no Handoff foram **medidas por reflexão sobre a assembly 1.20.0** em 2026-09-08. Last-verified: 2026-09-08.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -91,12 +91,59 @@ Use `AgentWorkflowBuilder.BuildSequential(agent1, agent2, ...)` quando precisar
|
|
|
91
91
|
|
|
92
92
|
Um agent de triagem decide qual especialista assume o controle com base no contexto. Útil quando há N especialistas e a decisão de roteamento é complexa demais para uma tool simples.
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
**Status: graduou.** O Handoff era marcado experimental no 1.0 e foi anunciado como *"graduating to release"* no BUILD 2026 (2026-06-03). **Medido em 2026-09-08:** `Microsoft.Agents.AI.Workflows.HandoffWorkflowBuilder` e `AgentWorkflowBuilder` **não carregam** `[Experimental]` na assembly 1.20.0 — a graduação está no binário, não só no anúncio.
|
|
95
|
+
|
|
96
|
+
Para handoff baseado em Workflow: `AgentWorkflowBuilder.CreateHandoffBuilderWith(triageAgent)`. Ver `ai-agents-workflows` para o padrão completo.
|
|
97
|
+
|
|
98
|
+
**Limites documentados, e o que cada um evita** (assinaturas medidas em `HandoffWorkflowBuilderCore<TBuilder>`):
|
|
99
|
+
|
|
100
|
+
| Limite | Como | O que evita |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| Teto de turnos | `.WithAutonomousMode(turnLimit: 8)` — aceita também `agentTurnLimits` por agente | Loop infinito de dois agentes se devolvendo a conversa |
|
|
103
|
+
| Condição de término | `.WithTerminationCondition(...)` | O mesmo, por critério de conteúdo em vez de contagem |
|
|
104
|
+
| `Id` estável por agente | Cada `AIAgent` com `Id` fixo (não regenerado a cada boot) | Handoff que aponta para um agente que "sumiu" entre reinícios |
|
|
105
|
+
| Group chat pequeno | ≤ **3** agentes por group chat | Acima disso o gerente gasta mais turnos escolhendo quem fala do que resolvendo |
|
|
95
106
|
|
|
96
107
|
> Para roteamento simples (2-3 caminhos), considere Agent-as-Tool com um agent por caminho antes de ir para Handoff Workflow.
|
|
97
108
|
|
|
98
109
|
---
|
|
99
110
|
|
|
111
|
+
## Agente auxiliar: em SEQUÊNCIA, nunca dentro de uma tool
|
|
112
|
+
|
|
113
|
+
**Anti-padrão medido em campo.** É tentador embrulhar um agente auxiliar (resumidor, classificador, extrator) numa tool do agente principal: parece composição barata. Não é.
|
|
114
|
+
|
|
115
|
+
```csharp
|
|
116
|
+
// ERRADO — o auxiliar roda DENTRO da tool do principal.
|
|
117
|
+
AIFunction summarize = AIFunctionFactory.Create(async (string text) =>
|
|
118
|
+
{
|
|
119
|
+
var r = await _summarizerAgent.RunAsync(text); // agente aninhado na tool
|
|
120
|
+
return r.Text;
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Dois problemas concretos:**
|
|
125
|
+
|
|
126
|
+
1. **`CallId` com tools encadeadas.** O agente auxiliar tem o próprio ciclo de tool calling. Rodando dentro da tool do principal, dois laços de function-calling se sobrepõem no mesmo turno, e a reconciliação de `CallId` entre pedido e resultado passa a depender da ordem em que os dois laços terminam.
|
|
127
|
+
2. **O loop do principal fica aberto enquanto o auxiliar roda.** O principal está no meio de um turno, com uma chamada pendente, esperando algo que pode levar várias voltas de LLM. Timeout, retry e telemetria do turno principal passam a medir a soma dos dois.
|
|
128
|
+
|
|
129
|
+
**O contrato correto são DUAS chamadas visíveis, em sequência:**
|
|
130
|
+
|
|
131
|
+
```csharp
|
|
132
|
+
// CERTO — o auxiliar roda FORA, e o resultado entra como dado no turno seguinte.
|
|
133
|
+
AgentResponse summary = await _summarizerAgent.RunAsync(text);
|
|
134
|
+
AgentResponse answer = await _mainAgent.RunAsync(
|
|
135
|
+
$"Resumo do documento:
|
|
136
|
+
{summary.Text}
|
|
137
|
+
|
|
138
|
+
Pergunta: {question}", session);
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Cada chamada tem o próprio span, o próprio custo e o próprio timeout — e o orquestrador é o **código**, não o modelo. É o mesmo princípio do compositor determinístico em `ai-agents-context-providers`.
|
|
142
|
+
|
|
143
|
+
**A exceção, com regra:** `agent.AsAIFunction()` é a composição barata **antes** de qualquer orquestração — e serve exatamente quando o LLM principal precisa **decidir** se chama o auxiliar. Nesse caso vale o teto: **aninhamento ≤ 2 níveis** (pai → filho). Um terceiro nível é sinal de que a composição devia ser sequência no código.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
100
147
|
## Decision tree
|
|
101
148
|
|
|
102
149
|
```
|
|
@@ -126,7 +173,11 @@ Tenho múltiplos agents — qual padrão usar?
|
|
|
126
173
|
| Usar multi-agent quando um único agent resolve | Adiciona latência, custo e superfície de erro sem ganho | Single agent com tools. Ver `ai-agents-sweet-spot`. |
|
|
127
174
|
| Usar Workflow quando Agent-as-Tool basta | Workflow traz edges, builders, streaming — complexidade desnecessária | `agent.AsAIFunction()` primeiro |
|
|
128
175
|
| Passar histórico de conversa bruto entre agents | Output do LLM é não-determinístico; o outro agent não sabe o que fazer com histórico livre | Structured Output entre agents. Ver `ai-agents-structured-output`. |
|
|
129
|
-
| Nesting profundo (agent A chama B chama C chama D) | Dificulta debug, amplifica latência, falhas em cascata | Achate a composição: Agent-as-Tool com o agent folha direto no pai. |
|
|
176
|
+
| Nesting profundo (agent A chama B chama C chama D) | Dificulta debug, amplifica latência, falhas em cascata | Achate a composição: Agent-as-Tool com o agent folha direto no pai; teto de **2** níveis. |
|
|
177
|
+
| **Agente auxiliar aninhado dentro de uma tool** | Dois laços de function-calling no mesmo turno (reconciliação de `CallId`) e o turno do principal aberto enquanto o auxiliar roda | Duas chamadas visíveis, auxiliar **em sequência**, fora da tool |
|
|
178
|
+
| Handoff sem `turnLimit` nem condição de término | Dois agentes devolvem a conversa um ao outro indefinidamente | `.WithAutonomousMode(turnLimit:)` ou `.WithTerminationCondition(...)` |
|
|
179
|
+
| `Id` de agente gerado a cada boot num workflow de handoff | O destino do handoff deixa de existir entre reinícios | `Id` estável, vindo de configuração |
|
|
180
|
+
| Group chat com 5+ agentes | O gerente gasta os turnos escolhendo quem fala | ≤ 3 agentes; acima disso, repense a decomposição |
|
|
130
181
|
| Agents com responsabilidades sobrepostas | Nenhum dos dois sabe quando agir; o LLM fica confuso | Fronteiras claras de responsabilidade; documente em `decisions.md`. |
|
|
131
182
|
|
|
132
183
|
---
|
|
@@ -139,6 +190,9 @@ Tenho múltiplos agents — qual padrão usar?
|
|
|
139
190
|
- [ ] Agents usando alias do Model Registry — nenhum model string hardcoded?
|
|
140
191
|
- [ ] Structured Output entre agents onde o output de um é input do outro?
|
|
141
192
|
- [ ] Nesting máximo de 2 níveis (pai → filho) sem cascata profunda?
|
|
193
|
+
- [ ] Nenhum agente auxiliar roda dentro de uma tool de outro agente — auxiliares são chamadas em sequência, no código?
|
|
194
|
+
- [ ] Todo workflow de handoff tem `turnLimit` **ou** condição de término, e os agentes têm `Id` estável?
|
|
195
|
+
- [ ] Group chat (se houver) tem no máximo 3 agentes?
|
|
142
196
|
|
|
143
197
|
---
|
|
144
198
|
|
|
@@ -149,7 +203,9 @@ Tenho múltiplos agents — qual padrão usar?
|
|
|
149
203
|
- `ai-agents-setup` — pacotes, DI, `AsAIAgent`
|
|
150
204
|
- `ai-agents-structured-output` — output tipado entre agents
|
|
151
205
|
- `ai-agents-providers-model-registry` — Model Registry alias pattern
|
|
206
|
+
- `ai-agents-context-providers` — o compositor determinístico: o código decide o modo, o LLM classifica
|
|
207
|
+
- `ai-agents-observability-patterns` — por que "uma chamada, um span" importa para medir latência
|
|
152
208
|
|
|
153
209
|
---
|
|
154
210
|
|
|
155
|
-
*MORPH-SPEC by Polymorphism Tech — ai-agents/multi-agent-patterns.md
|
|
211
|
+
*MORPH-SPEC by Polymorphism Tech — ai-agents/multi-agent-patterns.md v2.0 (2026-09-08)*
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
> **Keywords:** observability, telemetry, opentelemetry, logging, tracing, log investigation, troubleshooting, aspire dashboard, span, correlation id
|
|
6
6
|
> **Read by Claude in:** implement (wiring telemetry into an agent) and troubleshoot (investigating a production issue)
|
|
7
7
|
|
|
8
|
-
**Verified against:**
|
|
8
|
+
**Verified against:** Microsoft.Agents.AI 1.20.0 + Microsoft.Extensions.AI 10.9.0 (ai-pin 2026-09-08); `provado por templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphOpenTelemetryExtensions.cs` — o guard de span duplicado, a regra de "um nível, uma instrumentação" e o default `EnableSensitiveData = false` são exatamente o que o kit compila, com os spans contados em `tests/Morph.AiKit.Tests/TelemetryTests.cs`. Nomes de símbolo, de span, de métrica e das duas `ActivitySource` foram **medidos por reflexão e por leitura dos literais das assemblies do pin** em 2026-09-08, e em 2026-09-09 **todos os treze nomes `gen_ai.*` desta página** foram remedidos, um a um, por **teste de exclusividade**: os quatro `SetTag` da seção *Enrichment* e os nove das seções de span, métrica e atributo de agente. **Os treze existem** — depois de uma correção: `gen_ai.response.finish_reason`, no **singular**, não existia, só aparecia como cabeça de `finish_reason`**s**, e sobreviveu a duas varreduras porque as duas usaram `includes` — e **`includes` de um prefixo não prova o literal autônomo**. Os treze estão tabelados, em **duas** tabelas com propósitos diferentes: a de *Enrichment* registra os **4** `SetTag` daquele bloco (mais os **cinco** nomes rejeitados: o `finish_reason` singular, `PromptTokens`, `CompletionTokens`, `prompt_tokens` e `completion_tokens`), e a de distribuição, na seção *Nomes de span, métricas e atributos — medidos*, registra os **13** por assembly. A conferência é reproduzível por `node scripts/api-probe/probe.mjs tags` sobre este arquivo. A **instabilidade da convenção** — o split do semconv **v1.42.0 (2026-06-12)**, que depreciou e moveu todo `gen_ai.*` para `open-telemetry/semantic-conventions-genai`, onde nada GenAI está `Stable`, contra a v1.37 que o `OpenTelemetryChatClient` declara implementar — é **verificação documental**, apurada em 2026-09-08. Last-verified: 2026-09-08.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -17,28 +17,45 @@ Um agente MAF em produção não é uma função — é uma cadeia (LLM call →
|
|
|
17
17
|
|
|
18
18
|
## Setup — OpenTelemetry
|
|
19
19
|
|
|
20
|
+
### Duas correções medidas contra a versão anterior deste standard
|
|
21
|
+
|
|
22
|
+
| O que este standard dizia | O que o pin diz (medido em 2026-09-08) |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `AgentOpenTelemetryConsts.DefaultSourceName` e `agent.WithOpenTelemetry()` | **Nenhum dos dois existe** em `Microsoft.Agents.AI` 1.20.0. A API é `builder.UseOpenTelemetry(sourceName, configure)` sobre `AIAgentBuilder` / `ChatClientBuilder` |
|
|
25
|
+
| `EnableSensitiveTelemetryData` | O símbolo é **`EnableSensitiveData`**, e existe **nos dois** tipos: `OpenTelemetryAgent.EnableSensitiveData` e `OpenTelemetryChatClient.EnableSensitiveData`. Não são dois nomes diferentes: é o **mesmo nome em dois níveis** |
|
|
26
|
+
| *"não use `Experimental.Microsoft.Extensions.AI.*` — é do 9.x"* | São **duas fontes vivas e necessárias**: `Experimental.Microsoft.Agents.AI` (do agente) e `Experimental.Microsoft.Extensions.AI` (do chat e das tools). Quem só registra a primeira perde os spans `chat` e `execute_tool` |
|
|
27
|
+
|
|
28
|
+
Os dois nomes de `ActivitySource` foram lidos como literais nas assemblies `Microsoft.Agents.AI.dll` 1.20.0 e `Microsoft.Extensions.AI.dll` 10.9.0.
|
|
29
|
+
|
|
20
30
|
```csharp
|
|
21
31
|
using OpenTelemetry;
|
|
22
32
|
using OpenTelemetry.Trace;
|
|
23
33
|
using OpenTelemetry.Metrics;
|
|
24
34
|
using Microsoft.Agents.AI;
|
|
35
|
+
using Microsoft.Extensions.AI;
|
|
25
36
|
|
|
26
|
-
|
|
27
|
-
|
|
37
|
+
const string AgentSource = "Experimental.Microsoft.Agents.AI"; // span invoke_agent
|
|
38
|
+
const string ChatSource = "Experimental.Microsoft.Extensions.AI"; // spans chat e execute_tool
|
|
39
|
+
|
|
40
|
+
// Instrumentar o AGENTE (span externo). EnableSensitiveData default = false.
|
|
41
|
+
AIAgent instrumented = agent.AsBuilder()
|
|
42
|
+
.UseOpenTelemetry(sourceName: AgentSource, configure: o => o.EnableSensitiveData = false)
|
|
43
|
+
.Build();
|
|
28
44
|
|
|
29
45
|
// Program.cs — setup completo
|
|
30
46
|
builder.Services.AddOpenTelemetry()
|
|
31
47
|
.WithTracing(tracing =>
|
|
32
48
|
{
|
|
33
|
-
tracing.AddSource(
|
|
34
|
-
tracing.AddSource(
|
|
49
|
+
tracing.AddSource(AgentSource); // sem isto: nenhum invoke_agent
|
|
50
|
+
tracing.AddSource(ChatSource); // sem isto: nenhum chat / execute_tool
|
|
51
|
+
tracing.AddSource(builder.Environment.ApplicationName); // seus spans customizados (ver Enrichment)
|
|
35
52
|
tracing.AddAspNetCoreInstrumentation();
|
|
36
53
|
tracing.AddHttpClientInstrumentation();
|
|
37
54
|
tracing.AddOtlpExporter();
|
|
38
55
|
})
|
|
39
56
|
.WithMetrics(metrics =>
|
|
40
57
|
{
|
|
41
|
-
metrics.AddMeter(
|
|
58
|
+
metrics.AddMeter(ChatSource); // as métricas gen_ai.client.* saem daqui
|
|
42
59
|
metrics.AddAspNetCoreInstrumentation();
|
|
43
60
|
metrics.AddHttpClientInstrumentation();
|
|
44
61
|
metrics.AddRuntimeInstrumentation();
|
|
@@ -52,9 +69,99 @@ builder.Logging.AddOpenTelemetry(logging =>
|
|
|
52
69
|
});
|
|
53
70
|
```
|
|
54
71
|
|
|
55
|
-
> **
|
|
56
|
-
|
|
57
|
-
|
|
72
|
+
> **Produção:** `EnableSensitiveData = false` (é o default nos dois níveis) para não vazar prompt/response completos no backend de export.
|
|
73
|
+
|
|
74
|
+
### A regra de duplicação — um NÍVEL, uma instrumentação
|
|
75
|
+
|
|
76
|
+
A mudança de **1.6.1** (2026-05-14) foi o `OpenTelemetryAgent` passar a **auto-encapsular** o chat client com um `OpenTelemetryChatClient` no pipeline que o `ChatClientAgent` monta sozinho. Daí saiu a regra folclórica *"instrumente o agente **ou** o chat client, nunca os dois"* — que é **imprecisa**, e a diferença muda o que se escreve.
|
|
77
|
+
|
|
78
|
+
**O que foi medido no pin** (`Morph.AiKit.Tests/TelemetryTests.cs`, contra `Microsoft.Agents.AI` 1.20.0):
|
|
79
|
+
|
|
80
|
+
- Uma invocação instrumentada produz **`invoke_agent` (raiz) + `chat` (filho)**. Instrumentar os **dois níveis** é o caminho normal, e **não** duplica nada — o teste `AnInstrumentedAgentEmitsOneInvokeAgentSpanAndOneChatSpan` pina isso.
|
|
81
|
+
- O que duplica é **duas camadas no MESMO nível**: dois `OpenTelemetryChatClient` dão dois `chat`; dois `OpenTelemetryAgent` dão dois `invoke_agent` (`ForcingInstrumentChatClientProducesTheDuplicateChatSpan`).
|
|
82
|
+
- O guard do MAF **só alcança o pipeline que o `ChatClientAgent` monta sozinho**. Quem monta o próprio pipeline (`ChatClientAgentOptions.UseProvidedChatClientAsIs = true`, necessário para posicionar middleware de custo ou ajustar tool calling) **perde** esse slot: medido, agente instrumentado + pipeline próprio sem instrumentação de chat = **zero** spans de chat.
|
|
83
|
+
|
|
84
|
+
**A regra correta, então, é em duas linhas:**
|
|
85
|
+
|
|
86
|
+
1. **Instrumente cada nível no máximo uma vez.** O predicado é respondível, não um palpite: `inner.GetService(typeof(OpenTelemetryChatClient))` / `typeof(OpenTelemetryAgent)` atravessa a cadeia de delegates.
|
|
87
|
+
2. **Com pipeline próprio, a instrumentação de chat é obrigatória** — não é um extra opcional, é a única coisa que produz o span `chat`.
|
|
88
|
+
|
|
89
|
+
```csharp
|
|
90
|
+
// O guard, na forma que o ai-kit compila: nulo = instrumenta só o que ainda não está.
|
|
91
|
+
builder.Use(inner => inner.GetService(typeof(OpenTelemetryChatClient)) is null
|
|
92
|
+
? new OpenTelemetryChatClient(inner, logger: null, sourceName: ChatSource) { EnableSensitiveData = false }
|
|
93
|
+
: inner);
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Onde o span de chat fica no pipeline:** **abaixo** do `FunctionInvokingChatClient`. É assim que o span `chat` fecha antes das tools e o `invoke_agent` fica sendo a raiz. Ver a ordem completa do pipeline em `ai-agents-middleware-patterns`.
|
|
97
|
+
|
|
98
|
+
### Nomes de span, métricas e atributos — medidos
|
|
99
|
+
|
|
100
|
+
| O que | Nome | Onde foi medido |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| Span do agente | `invoke_agent` | literal em `Microsoft.Agents.AI.dll` 1.20.0 |
|
|
103
|
+
| Span do modelo | operação + modelo (`gen_ai.operation.name` + `gen_ai.request.model`) | `Microsoft.Extensions.AI.dll` 10.9.0 |
|
|
104
|
+
| Span de tool | `execute_tool` | `Microsoft.Extensions.AI.dll` 10.9.0 |
|
|
105
|
+
| Métrica de duração | `gen_ai.client.operation.duration` | idem |
|
|
106
|
+
| Métrica de tokens | `gen_ai.client.token.usage` | idem |
|
|
107
|
+
| Métricas extras | `gen_ai.client.operation.exception`, `gen_ai.client.operation.time_per_output_chunk` | idem |
|
|
108
|
+
| Atributos do agente | `gen_ai.agent.id`, `gen_ai.agent.name`, `gen_ai.agent.description`, `gen_ai.provider.name` | `Microsoft.Agents.AI.dll` 1.20.0 |
|
|
109
|
+
|
|
110
|
+
A coluna "onde foi medido" nomeia **uma** assembly onde o literal ocorre, e **não** afirma
|
|
111
|
+
exclusividade. A distribuição completa, medida por exclusividade sobre **todas** as assemblies
|
|
112
|
+
restauradas do pin (`probe.mjs tags`, 2026-09-09) — repare que ela **não se limita às duas** que esta
|
|
113
|
+
página nomeia:
|
|
114
|
+
|
|
115
|
+
| Nome | Assemblies onde o literal ocorre |
|
|
116
|
+
|---|---|
|
|
117
|
+
| `invoke_agent` | `Microsoft.Agents.AI` **e** `Microsoft.Extensions.AI` |
|
|
118
|
+
| `execute_tool` | `Microsoft.Extensions.AI` **e** `ModelContextProtocol.Core` |
|
|
119
|
+
| `gen_ai.agent.id`, `gen_ai.agent.name`, `gen_ai.agent.description` | **só** `Microsoft.Agents.AI` |
|
|
120
|
+
| `gen_ai.provider.name` | `Microsoft.Agents.AI` **e** `Microsoft.Extensions.AI` |
|
|
121
|
+
| `gen_ai.operation.name` | `Microsoft.Agents.AI`, `Microsoft.Extensions.AI`, `ModelContextProtocol.Core` **e** `OpenAI` |
|
|
122
|
+
| `gen_ai.request.model`, `gen_ai.usage.input_tokens`, `gen_ai.usage.output_tokens`, `gen_ai.response.finish_reasons`, `gen_ai.client.operation.duration`, `gen_ai.client.token.usage` | `Microsoft.Extensions.AI` **e** `OpenAI` |
|
|
123
|
+
| `gen_ai.client.operation.exception`, `gen_ai.client.operation.time_per_output_chunk` | **só** `Microsoft.Extensions.AI` |
|
|
124
|
+
|
|
125
|
+
**Por que isto importa para quem instrumenta:** o mesmo nome emitido por camadas diferentes é o que
|
|
126
|
+
produz span duplicado — e é a razão de este standard começar pelo guard de "um nível, uma
|
|
127
|
+
instrumentação". `OpenAI` e `ModelContextProtocol.Core` estão sob o **mesmo pin** e carregam parte
|
|
128
|
+
destes nomes; se você registrar a fonte deles junto com a do agente sem o guard, o atributo chega
|
|
129
|
+
duas vezes com procedências diferentes.
|
|
130
|
+
|
|
131
|
+
> **Duas afirmações que NÃO se confirmaram, e por isso não estão acima.** `agent_framework.function.invocation.duration` e a variável de ambiente `OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental` **não aparecem** em nenhuma das quatro assemblies do pin (`Microsoft.Agents.AI`, `.Abstractions`, `Microsoft.Extensions.AI`, `.Abstractions`), varridas por literal em 2026-09-08. A duração de invocação de função pode existir noutro pacote, e a variável é do SDK do OpenTelemetry, não destes pacotes — em nenhum dos dois casos este standard as prescreve sem fonte.
|
|
132
|
+
|
|
133
|
+
### Estabilidade da convenção GenAI — a ressalva que muda como ler a tabela acima
|
|
134
|
+
|
|
135
|
+
Os nomes acima são **medidos nas assemblies do pin**, e continuam corretos. O que não é estável é a
|
|
136
|
+
**convenção** que eles implementam, e um standard que manda instrumentar sem dizer isso está mandando
|
|
137
|
+
pintar alvo num muro que se move.
|
|
138
|
+
|
|
139
|
+
Os fatos, apurados em 2026-09-08:
|
|
140
|
+
|
|
141
|
+
- As **GenAI semantic conventions saíram do repositório principal** do OpenTelemetry. A versão
|
|
142
|
+
**1.42.0 do semconv (2026-06-12)** depreciou e moveu todo o namespace `gen_ai.*`; a **1.43.0
|
|
143
|
+
(2026-07-03)** não traz nenhum.
|
|
144
|
+
- O conteúdo passou a viver em `open-telemetry/semantic-conventions-genai`, e ali **nenhum** span,
|
|
145
|
+
evento, métrica ou atributo GenAI está marcado `Stable` — todos estão em `Development`. Os únicos
|
|
146
|
+
estáveis no conjunto são `error.type`, `server.address` e `server.port`, que são **atributos
|
|
147
|
+
comuns**, não GenAI.
|
|
148
|
+
- Enquanto isso, o `OpenTelemetryChatClient` do `Microsoft.Extensions.AI` declara implementar a
|
|
149
|
+
**v1.37** — ou seja, a versão implementada está **atrás** do split.
|
|
150
|
+
|
|
151
|
+
**O que isso implica na prática, e é o que se leva daqui:**
|
|
152
|
+
|
|
153
|
+
| Implicação | O que fazer |
|
|
154
|
+
|---|---|
|
|
155
|
+
| Nome de atributo `gen_ai.*` pode mudar entre versões do pacote | Não construa alerta cujo único identificador seja um nome `gen_ai.*` sem um plano de renomeação |
|
|
156
|
+
| A versão implementada pelo pacote **não** é a última da convenção | Ao subir o pin, confira a tabela de nomes acima em vez de assumir continuidade |
|
|
157
|
+
| Painel montado sobre o namespace instável envelhece com o pacote | Vale a pena manter uma camada própria de nomes (`morph.*`) para o que o time consulta todo dia |
|
|
158
|
+
|
|
159
|
+
Isto **não** é motivo para não instrumentar. É motivo para instrumentar sabendo que os nomes são de
|
|
160
|
+
uma convenção em desenvolvimento, e para não tratar uma renomeação futura como incidente.
|
|
161
|
+
|
|
162
|
+
### Limitação conhecida, em aberto
|
|
163
|
+
|
|
164
|
+
Issue **3637** do `microsoft/agent-framework`: o `UseOpenTelemetry()` do .NET **não emite `ActivityEvent`s** conforme a spec de eventos GenAI — o conteúdo de mensagem viaja como atributo, não como evento. Estado em 2026-09-08: **aberta**. Consequência prática: um backend que monta a conversa a partir de *events* GenAI mostra spans sem mensagens. Não é bug do seu wiring.
|
|
58
165
|
|
|
59
166
|
### Aspire Dashboard (dev/local)
|
|
60
167
|
|
|
@@ -81,12 +188,54 @@ Sem um `correlation_id` propagado manualmente através de chamadas assíncronas/
|
|
|
81
188
|
|
|
82
189
|
```csharp
|
|
83
190
|
activity?.SetTag("gen_ai.request.model", modelAlias); // alias do Model Registry, nunca o nome hardcoded
|
|
84
|
-
activity?.SetTag("gen_ai.usage.
|
|
85
|
-
activity?.SetTag("gen_ai.usage.
|
|
86
|
-
activity?.SetTag("gen_ai.response.
|
|
191
|
+
activity?.SetTag("gen_ai.usage.input_tokens", usage.InputTokenCount);
|
|
192
|
+
activity?.SetTag("gen_ai.usage.output_tokens", usage.OutputTokenCount);
|
|
193
|
+
activity?.SetTag("gen_ai.response.finish_reasons", finishReasons); // PLURAL — o singular não existe no pin
|
|
87
194
|
```
|
|
88
195
|
|
|
89
|
-
|
|
196
|
+
> **Correção de 2026-09-09 (duas passadas), medida por reflexão e por literal nas assemblies do
|
|
197
|
+
> pin. As QUATRO linhas acima foram conferidas, uma a uma** — a primeira passada corrigiu duas e
|
|
198
|
+
> deixou uma errada no mesmo bloco, que é a razão de este callout listar todas em vez de só as que
|
|
199
|
+
> mudaram.
|
|
200
|
+
>
|
|
201
|
+
> | Tag / símbolo | Veredito | Como |
|
|
202
|
+
> |---|---|---|
|
|
203
|
+
> | `gen_ai.request.model` | **existe** | 2 ocorrências autônomas; **distribuição por assembly na tabela da seção _Nomes de span, métricas e atributos — medidos_** — não é exclusivo de uma |
|
|
204
|
+
> | `gen_ai.usage.input_tokens` | **existe** | 2 autônomas; distribuição na tabela citada acima |
|
|
205
|
+
> | `gen_ai.usage.output_tokens` | **existe** | 2 autônomas; distribuição na tabela citada acima |
|
|
206
|
+
> | `gen_ai.response.finish_reasons` (a linha acima, no **plural**) | **existe** | 2 autônomas; distribuição na tabela citada acima |
|
|
207
|
+
> | `gen_ai.response.finish_reason` (o **singular**, que estava aqui) | **NÃO existe** | as **mesmas** 2 ocorrências do plural, **nenhuma autônoma**: o singular é a cabeça de `finish_reason`**s** |
|
|
208
|
+
> | `usage.PromptTokens` / `CompletionTokens` | **NÃO existem** | 0 ocorrências autônomas em assembly restaurada nenhuma |
|
|
209
|
+
> | `gen_ai.usage.prompt_tokens` / `completion_tokens` | **NÃO existem** | 0 ocorrências autônomas em assembly restaurada nenhuma |
|
|
210
|
+
>
|
|
211
|
+
> O que existe no lugar dos dois últimos é `InputTokenCount` / `OutputTokenCount`, propriedades de
|
|
212
|
+
> `UsageDetails` — que vive na assembly **`Microsoft.Extensions.AI.Abstractions` 10.9.0** (que viaja dentro do pacote `Microsoft.Extensions.AI`, e não é id de pacote do pin), e não na assembly
|
|
213
|
+
> que carrega os literais. E **"a assembly que carrega os literais" não é uma só** — a distribuição
|
|
214
|
+
> completa, por nome, está na tabela da seção *Nomes de span, métricas e atributos — medidos*, e **esta linha não a
|
|
215
|
+
> repete**: uma segunda tabela dos mesmos nomes foi escrita aqui na rodada 5 e **contradizia** a
|
|
216
|
+
> primeira (dizia "só em `Microsoft.Extensions.AI`" para seis literais que também vivem em `OpenAI`),
|
|
217
|
+
> justamente por invocá-la como autoridade sem relê-la. Duas cópias do mesmo fato divergem; a
|
|
218
|
+
> segunda foi removida.
|
|
219
|
+
>
|
|
220
|
+
> Faz sentido: quem **emite** o span de chamada de modelo é `OpenTelemetryChatClient`
|
|
221
|
+
> (`Microsoft.Extensions.AI` 10.9.0); quem descreve o **agente** é a camada de agente. Os nomes
|
|
222
|
+
> velhos eram da convenção **anterior** à renomeação do semconv. Código copiado daqui não compilava,
|
|
223
|
+
> e a tag emitida não casaria com nenhum painel montado sobre a convenção atual.
|
|
224
|
+
>
|
|
225
|
+
> **O método importa tanto quanto o resultado:** `finish_reason` sobreviveu a duas varreduras porque
|
|
226
|
+
> as duas usaram `includes(literal)`, e **`includes` de um prefixo não prova o literal autônomo** —
|
|
227
|
+
> o singular casa dentro do plural. A conferência acima é por **exclusividade**: cada ocorrência é
|
|
228
|
+
> aceita só se o caractere anterior e o seguinte não forem `[A-Za-z0-9_.-]`. Literais de string .NET
|
|
229
|
+
> vivem no heap `#US` em **UTF-16**; a varredura cobre `#US` (UTF-16) e `#Strings` (ASCII).
|
|
230
|
+
|
|
231
|
+
Nomeação `gen_ai.*` segue a convenção semântica OpenTelemetry para GenAI — mantém compatibilidade se o backend de observability tiver dashboards prontos para essa convenção. Sobre a **instabilidade** dessa convenção, ver a ressalva na seção de Setup.
|
|
232
|
+
|
|
233
|
+
> **Tokens ficam aqui; dinheiro não.** A **tarifa** por alias (com data de verificação), o **cálculo**
|
|
234
|
+
> do custo (e as três armadilhas de fórmula: raciocínio cobrado como saída, entrada cacheada como
|
|
235
|
+
> subconjunto da entrada, taxa fixa de operação hospedada), o estado de um custo
|
|
236
|
+
> (`Computed`/`Waived`/`UsageMissing`, e por que `cost_usd` nunca é nulo) e o **teto de orçamento**
|
|
237
|
+
> têm **tratamento canônico** em **`ai-agents-cost-and-budget`**. Não duplicado aqui. A delegação é
|
|
238
|
+
> de mão dupla: aquele standard aponta de volta para esta seção quando o assunto é atributo de span.
|
|
90
239
|
|
|
91
240
|
### Logging estruturado com `ILogger` — sempre com scope
|
|
92
241
|
|
|
@@ -105,11 +254,57 @@ using (_logger.BeginScope(new Dictionary<string, object>
|
|
|
105
254
|
```
|
|
106
255
|
|
|
107
256
|
- **Sempre** parâmetros nomeados no template (`{ToolName}`, não string interpolada) — permite querying estruturado no backend em vez de grep de texto livre.
|
|
108
|
-
- **Nunca** logar o conteúdo completo do prompt/response em `Information` — isso é PII/dado sensível do cliente por padrão. Logar em `Debug` apenas, e só se `
|
|
257
|
+
- **Nunca** logar o conteúdo completo do prompt/response em `Information` — isso é PII/dado sensível do cliente por padrão. Logar em `Debug` apenas, e só se `EnableSensitiveData` estiver habilitado explicitamente para o ambiente.
|
|
109
258
|
- **Nível de log por tipo de evento:** `Information` para início/fim de tool call e decisões do agent; `Warning` para retry/fallback de provider; `Error` apenas para falhas que geram resposta degradada ao usuário (não para toda exceção capturada e tratada).
|
|
110
259
|
|
|
111
260
|
---
|
|
112
261
|
|
|
262
|
+
## Rastreabilidade do que foi ao provedor
|
|
263
|
+
|
|
264
|
+
A pergunta que a instrumentação existe para responder depois de um incidente é uma só: **dá para
|
|
265
|
+
reconstruir o que foi enviado ao provedor, e o que ele respondeu, neste turno?**
|
|
266
|
+
|
|
267
|
+
**A regra: prompt cru no harness; hash em produção.**
|
|
268
|
+
|
|
269
|
+
| Ambiente | O que se registra | Por quê |
|
|
270
|
+
|---|---|---|
|
|
271
|
+
| Dev e harness | O texto enviado, com **opt-in explícito** e sem dado pessoal | É onde se depura; o custo de vazamento é controlado |
|
|
272
|
+
| Produção | O **hash** do texto enviado (e, quando o prompt é composto de blocos, um hash por bloco) | Um prompt cru persistido em produção é um vazamento esperando indexação. O hash responde "foi o mesmo texto?" sem guardar o texto |
|
|
273
|
+
|
|
274
|
+
Isso é a mesma chave que `EnableSensitiveData = false` fora de dev já protege — e o hash é o que
|
|
275
|
+
sobra de útil depois de desligá-la.
|
|
276
|
+
|
|
277
|
+
### A invariante que torna o hash confiável
|
|
278
|
+
|
|
279
|
+
Um hash só prova alguma coisa se o texto de que ele é hash **é** o texto que foi enviado. Isso deixa
|
|
280
|
+
de valer no instante em que existe um cache entre a montagem e o envio: a partir dali, telemetria e
|
|
281
|
+
requisição podem divergir, e a divergência é silenciosa.
|
|
282
|
+
|
|
283
|
+
Por isso a exigência é do lado de quem monta o prompt, não de quem o registra: **o texto enviado é
|
|
284
|
+
derivado dos blocos, sem cache**. É uma invariante deliberadamente cara, e a razão está escrita no
|
|
285
|
+
código de campo que a implementa — *"para a telemetria não poder mentir"*. O tratamento canônico
|
|
286
|
+
está em `ai-agents-conversational-agent-with-phases`, seção do compositor de turno.
|
|
287
|
+
|
|
288
|
+
**Duas asserções que fecham o ciclo**, e ambas são de teste, não de wiring:
|
|
289
|
+
|
|
290
|
+
- A lista de tools **ofertadas** saiu da lista real do turno, e não de uma constante paralela.
|
|
291
|
+
- **Turno cancelado não grava** — um registro de algo que não aconteceu é pior que a ausência dele.
|
|
292
|
+
|
|
293
|
+
A metade de harness deste assunto (o que o fake captura, e como assertar sobre isso) é de
|
|
294
|
+
`ai-agents-testing-ai`. O veredito ternário e o escape registrado, que são o que torna um guard
|
|
295
|
+
auditável pela mesma via, são de `ai-agents-guardrails`.
|
|
296
|
+
|
|
297
|
+
> **O que o Gate 3 procura.** Os nomes concretos — `ActivitySource`, spans, métricas e atributos
|
|
298
|
+
> requeridos — estão medidos na tabela **"Nomes de span, métricas e atributos — medidos"** acima, e
|
|
299
|
+
> **não** são repetidos aqui: uma segunda lista dos mesmos nomes é a segunda verdade nascendo. A
|
|
300
|
+
> régua de avaliação correspondente vive em
|
|
301
|
+
> `.morph/framework/evals/proof-rubrics/observabilidade-genai.md`, e ela pergunta a **propriedade**
|
|
302
|
+
> desta seção (dá para reconstruir o turno?), não a tecnologia — porque uma régua binária "tem span?"
|
|
303
|
+
> daria a mesma nota a quem tem só a mensagem da exceção e a quem tem hash por bloco de prompt com
|
|
304
|
+
> teste de fidelidade.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
113
308
|
## Investigação e análise — quando algo dá errado
|
|
114
309
|
|
|
115
310
|
Workflow para diagnosticar um incidente relatado ("o agente X respondeu errado/lento/nada às HH:MM"):
|
|
@@ -134,12 +329,20 @@ Workflow para diagnosticar um incidente relatado ("o agente X respondeu errado/l
|
|
|
134
329
|
|
|
135
330
|
## Checklist (verifiable by morph-eval)
|
|
136
331
|
|
|
137
|
-
- [ ]
|
|
138
|
-
- [ ] `
|
|
332
|
+
- [ ] `AddSource` das **duas** fontes: `Experimental.Microsoft.Agents.AI` e `Experimental.Microsoft.Extensions.AI`
|
|
333
|
+
- [ ] Nenhuma referência a `AgentOpenTelemetryConsts` ou `agent.WithOpenTelemetry()` (não existem no pin)
|
|
334
|
+
- [ ] `EnableSensitiveData = false` fora de dev/staging (é o default — confirme que ninguém ligou)
|
|
335
|
+
- [ ] Cada nível instrumentado **no máximo uma vez**; com `UseProvidedChatClientAsIs = true`, a instrumentação de chat está explicitamente presente
|
|
336
|
+
- [ ] Um teste conta os spans de uma invocação: exatamente um `invoke_agent` e um `chat`
|
|
139
337
|
- [ ] Todo tool call relevante tem `correlation_id` propagado manualmente através de boundaries assíncronos (filas, background jobs)
|
|
140
338
|
- [ ] Logging via `ILogger` com `BeginScope` estruturado, nunca string interpolada em templates de log
|
|
141
339
|
- [ ] Nenhum log em `Information`/produção contém prompt/response completo
|
|
142
340
|
- [ ] Alertas configurados para os thresholds da tabela "What to Monitor" relevantes ao projeto
|
|
341
|
+
- [ ] Nenhum alerta depende de um nome `gen_ai.*` como identificador único sem plano de renomeação (a convenção está em `Development`, não `Stable`)
|
|
342
|
+
- [ ] Em produção, o que foi ao provedor é reconstituível por **hash**; prompt cru só em dev/harness, com opt-in
|
|
343
|
+
- [ ] O texto enviado é derivado dos blocos **sem cache** — sem isso o hash não prova nada
|
|
344
|
+
- [ ] Há asserção de que a lista de tools ofertadas saiu da lista real do turno
|
|
345
|
+
- [ ] Turno cancelado **não** grava telemetria
|
|
143
346
|
|
|
144
347
|
---
|
|
145
348
|
|
|
@@ -147,10 +350,17 @@ Workflow para diagnosticar um incidente relatado ("o agente X respondeu errado/l
|
|
|
147
350
|
|
|
148
351
|
- `ai-agents-production` — panorama de produção; esta seção era resumida lá, tratamento canônico agora aqui
|
|
149
352
|
- `ai-agents-middleware-patterns` — middleware de telemetria no nível `IChatClient` (`TelemetryMiddleware`)
|
|
353
|
+
- `ai-agents-cost-and-budget` — tarifa, cálculo de custo e teto de orçamento (delegação recíproca: tokens ficam aqui, dinheiro fica lá)
|
|
354
|
+
- `ai-agents-conversational-agent-with-phases` — o compositor de turno e a invariante "derivado sem cache" que torna o hash confiável
|
|
355
|
+
- `ai-agents-testing-ai` — a metade de harness da rastreabilidade (captura do fake, prompt cru com opt-in)
|
|
356
|
+
- `ai-agents-guardrails` — veredito ternário e escape registrado, auditáveis pela mesma telemetria
|
|
357
|
+
- `.morph/framework/evals/proof-rubrics/observabilidade-genai.md` — a régua do Gate 3 para a propriedade desta seção
|
|
150
358
|
- `infrastructure-docker-coolify-deploy` — Serilog/JSON console log para o pipeline de agregação em produção
|
|
359
|
+
- Reference implementation (compila e conta spans contra o pin): `templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphOpenTelemetryExtensions.cs` + `tests/Morph.AiKit.Tests/TelemetryTests.cs`
|
|
151
360
|
- [OpenTelemetry Semantic Conventions for GenAI](https://opentelemetry.io/docs/specs/semconv/gen-ai/)
|
|
152
361
|
- [Agent Observability](https://learn.microsoft.com/agent-framework/user-guide/observability/)
|
|
362
|
+
- Issue aberta `microsoft/agent-framework#3637` — `ActivityEvent`s da spec GenAI não emitidos (estado em 2026-09-08: **aberta**)
|
|
153
363
|
|
|
154
364
|
---
|
|
155
365
|
|
|
156
|
-
*MORPH-SPEC by Polymorphism Tech — ai-agents/observability-patterns.md
|
|
366
|
+
*MORPH-SPEC by Polymorphism Tech — ai-agents/observability-patterns.md v2.0 (2026-09-08)*
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
> **Keywords:** middleware, observability, telemetry, mcp, a2a, caching, anti-hallucination, production agent
|
|
6
6
|
> **Read by Claude in:** implement (when wiring middleware/telemetry/MCP into an agent)
|
|
7
7
|
|
|
8
|
-
**Verified against:**
|
|
8
|
+
**Verified against:** Microsoft.Agents.AI 1.20.0 (ai-pin 2026-09-08) + Microsoft.Agents.AI.Hosting `1.20.0-preview.260831.1` e Microsoft.Agents.AI.A2A `1.20.0-preview.260831.1` (**fora do pin**; versões apuradas no nuget.org em 2026-09-08). **Verificação documental**, sem cláusula `provado por` — este standard é panorama, e cada tema tem dono canônico noutro standard. Os nomes de isolamento multi-tenant foram **medidos por reflexão sobre `Microsoft.Agents.AI.Hosting`** em 2026-09-08. Last-verified: 2026-09-08.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -33,12 +33,15 @@ e os patterns de telemetria, resilência (retry + rate-limit) e anti-hallucinati
|
|
|
33
33
|
|
|
34
34
|
Exponha agents como serviços web interoperáveis via protocolo A2A padronizado.
|
|
35
35
|
|
|
36
|
-
**Package
|
|
36
|
+
**Package — PRERELEASE, e fora do `ai-pin.json`:**
|
|
37
37
|
|
|
38
38
|
```xml
|
|
39
|
-
|
|
39
|
+
<!-- Apurado no nuget.org em 2026-09-08: não há versão estável de Microsoft.Agents.AI.A2A. -->
|
|
40
|
+
<PackageReference Include="Microsoft.Agents.AI.A2A" Version="1.20.0-preview.260831.1" />
|
|
40
41
|
```
|
|
41
42
|
|
|
43
|
+
> **Correção de 2026-09-08:** a versão anterior deste standard rotulava o A2A como **GA** com faixa `1.0.*`. Nenhuma das duas coisas se sustenta: o pacote nunca teve versão estável, e faixa flutuante num SDK de cadência semanal é o defeito que `ai-agents-setup` §1 proíbe.
|
|
44
|
+
|
|
42
45
|
### Expor um agent via A2A
|
|
43
46
|
|
|
44
47
|
```csharp
|
|
@@ -181,7 +184,30 @@ public async Task<WeatherResponse> GetWeatherAsync(
|
|
|
181
184
|
|
|
182
185
|
Setup, enrichment (span attributes, correlation IDs, structured logging) e o workflow de investigação/análise de logs em produção têm **tratamento canônico** em **`ai-agents-observability-patterns`**. Não duplicado aqui.
|
|
183
186
|
|
|
184
|
-
> Em produção:
|
|
187
|
+
> Em produção: `AddSource` das **duas** fontes — `Experimental.Microsoft.Agents.AI` e `Experimental.Microsoft.Extensions.AI` — e `EnableSensitiveData = false` fora de dev/staging. (Correção de 2026-09-08: `AgentOpenTelemetryConsts` e `EnableSensitiveTelemetryData` **não existem** no pin; medido.) Ver `ai-agents-observability-patterns` para o setup completo, o que preencher em cada span/log, e o workflow de investigação quando um incidente for reportado.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Isolamento multi-tenant — renomeado em 1.18
|
|
192
|
+
|
|
193
|
+
Um agente registrado como singleton atende todos os tenants. O que separa um do outro não é o agente: é a **chave de isolamento** que decide de qual balde vem a sessão.
|
|
194
|
+
|
|
195
|
+
Na **1.18** (2026-08-18) essa superfície foi renomeada. Nomes atuais, medidos por reflexão sobre `Microsoft.Agents.AI.Hosting` (pacote `1.20.0-preview.260831.1`) em 2026-09-08:
|
|
196
|
+
|
|
197
|
+
| Tipo | Papel |
|
|
198
|
+
|---|---|
|
|
199
|
+
| `Microsoft.Agents.AI.Hosting.AgentIsolationKeyProvider` | Produz a chave de isolamento do request corrente |
|
|
200
|
+
| `Microsoft.Agents.AI.Hosting.IsolationKeyScopedAgentSessionStore` | O `AgentSessionStore` que aplica a chave; tem `IsolationKeyScopedAgentSessionStoreOptions` |
|
|
201
|
+
| `UseClaimsBasedAgentIsolation()` (ASP.NET Core) | Deriva a chave das claims do usuário autenticado |
|
|
202
|
+
|
|
203
|
+
**Duas advertências que valem mais que os nomes:**
|
|
204
|
+
|
|
205
|
+
1. **O pacote é prerelease.** `Microsoft.Agents.AI.Hosting` não tem versão estável (apurado 2026-09-08). Isolamento multi-tenant por esse caminho é adoção de preview — registre em `decisions.md`.
|
|
206
|
+
2. **A chave vem da credencial, nunca do payload.** Uma chave derivada de algo que o cliente envia é uma chave que o cliente escolhe. `UseClaimsBasedAgentIsolation()` existe exatamente para não deixar essa decisão passar pelo corpo do request.
|
|
207
|
+
|
|
208
|
+
### Invocação concorrente de tools é opt-in desde 1.18
|
|
209
|
+
|
|
210
|
+
`FunctionInvokingChatClient.AllowConcurrentInvocation` (exposto como `ChatClientAgentOptions.AllowConcurrentInvocation`) tem default **`false`**: numa volta com várias chamadas de tool, elas rodam **em sequência**. Ligar a concorrência é decisão explícita — e só é segura se **todas** as tools daquele agente forem thread-safe. Um `DbContext` do EF Core **não** é: duas tools concorrentes sobre o mesmo `DbContext` scoped produzem `InvalidOperationException` intermitente sob carga, que é o pior formato possível de bug.
|
|
185
211
|
|
|
186
212
|
---
|
|
187
213
|
|
|
@@ -194,18 +220,21 @@ Setup, enrichment (span attributes, correlation IDs, structured logging) e o wor
|
|
|
194
220
|
- [ ] Rate limiting middleware em agents expostos publicamente
|
|
195
221
|
- [ ] Endpoints A2A protegidos com autenticação
|
|
196
222
|
- [ ] Structured output usado para respostas — evita parsing de texto livre
|
|
197
|
-
- [ ] OpenTelemetry com `
|
|
223
|
+
- [ ] OpenTelemetry com `AddSource` das duas fontes `Experimental.Microsoft.*` configurado
|
|
224
|
+
- [ ] Multi-tenant: a chave de isolamento vem da credencial (claims), nunca do payload do request
|
|
198
225
|
|
|
199
226
|
---
|
|
200
227
|
|
|
201
228
|
## Production Checklist (verifiable by morph-eval)
|
|
202
229
|
|
|
203
|
-
- [ ] `Microsoft.Agents.AI` 1.0
|
|
230
|
+
- [ ] `Microsoft.Agents.AI` **1.20.0** (versão exata, do `ai-pin.json`) no `.csproj`; nenhum pacote SK de orquestração
|
|
231
|
+
- [ ] Nenhum `PackageReference` de SDK de IA com faixa flutuante; pacote fora do pin com versão exata + data de apuração
|
|
232
|
+
- [ ] `AllowConcurrentInvocation` continua `false`, ou todas as tools do agente são comprovadamente thread-safe
|
|
204
233
|
- [ ] Middleware registrado via `.AsBuilder().Use(...)` antes de `Build()`
|
|
205
234
|
- [ ] `ResilientToolMiddleware` (ou equivalente) em agents que chamam APIs externas
|
|
206
235
|
- [ ] Semantic cache configurado se o agent recebe queries repetitivas
|
|
207
|
-
- [ ] OpenTelemetry source = `
|
|
208
|
-
- [ ] Dados sensíveis de telemetry desabilitados em produção (`
|
|
236
|
+
- [ ] OpenTelemetry source = `Experimental.Microsoft.Agents.AI` **e** `Experimental.Microsoft.Extensions.AI`
|
|
237
|
+
- [ ] Dados sensíveis de telemetry desabilitados em produção (`EnableSensitiveData = false`)
|
|
209
238
|
- [ ] A2A endpoints com `MapA2A` protegidos por auth se expostos na internet
|
|
210
239
|
- [ ] MCP client `await using` para dispose correto do transporte
|
|
211
240
|
|
|
@@ -228,4 +257,4 @@ Setup, enrichment (span attributes, correlation IDs, structured logging) e o wor
|
|
|
228
257
|
|
|
229
258
|
---
|
|
230
259
|
|
|
231
|
-
*MORPH-SPEC by Polymorphism Tech — ai-agents/production.md
|
|
260
|
+
*MORPH-SPEC by Polymorphism Tech — ai-agents/production.md v3.0 (2026-09-08)*
|