@polymorphism-tech/morph-spec 8.33.0 → 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 +22 -2
- package/README.md +2 -2
- package/bin/morph-spec.js +43 -5
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +5 -4
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +2 -2
- package/framework/MORPH.md +20 -22
- package/framework/agents.json +198 -44
- package/framework/ai-pin.json +22 -0
- package/framework/commands/morph-media.md +45 -0
- package/framework/docs/CLI.md +238 -10
- 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/README.md +11 -1
- package/framework/hooks/claude-code/core/block-destructive-worktree-removal.js +5 -8
- package/framework/hooks/claude-code/core/block-raw-worktree-add.js +79 -0
- package/framework/hooks/claude-code/core/chain.js +27 -7
- package/framework/hooks/claude-code/core/protect-spec-files.js +41 -4
- package/framework/hooks/claude-code/core/worktree-context.js +83 -14
- package/framework/hooks/claude-code/core/worktree-create.js +206 -0
- package/framework/hooks/claude-code/core/worktree-env-inject.js +87 -0
- package/framework/hooks/claude-code/core/worktree-remove.js +81 -0
- package/framework/hooks/shared/command-tokens.js +23 -0
- package/framework/hooks/shared/e2e-check.js +0 -0
- package/framework/hooks/shared/git-paths.js +25 -0
- package/framework/hooks/shared/hook-response.js +17 -0
- package/framework/hooks/shared/morph-cli.js +134 -0
- package/framework/rules/ai-agents-standards.md +14 -2
- package/framework/rules/infrastructure-standards.md +3 -1
- 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 +28 -7
- 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 +20 -2
- package/framework/skills/core/morph-media/SKILL.md +215 -0
- package/framework/skills/core/morph-plan/SKILL.md +38 -4
- 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 +1504 -830
- package/framework/standards/ai-agents/agent-archetypes.md +160 -0
- package/framework/standards/ai-agents/agent-session.md +256 -160
- package/framework/standards/ai-agents/agent-spec.md +196 -0
- package/framework/standards/ai-agents/batching.md +217 -193
- package/framework/standards/ai-agents/context-providers.md +261 -188
- 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 +351 -250
- package/framework/standards/ai-agents/mcp-tools.md +250 -197
- 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 +241 -207
- package/framework/standards/ai-agents/modalities-image-gen.md +422 -173
- package/framework/standards/ai-agents/modalities-speech-to-text.md +177 -171
- package/framework/standards/ai-agents/modalities-text-to-speech.md +189 -181
- package/framework/standards/ai-agents/modalities-vision.md +205 -201
- package/framework/standards/ai-agents/multi-agent-patterns.md +211 -155
- package/framework/standards/ai-agents/observability-patterns.md +227 -17
- package/framework/standards/ai-agents/production.md +260 -231
- package/framework/standards/ai-agents/prompt-sources.md +389 -0
- package/framework/standards/ai-agents/providers/model-registry.md +293 -158
- package/framework/standards/ai-agents/rag-custom-pgvector.md +69 -4
- package/framework/standards/ai-agents/service-tier-flex.md +143 -135
- package/framework/standards/ai-agents/setup.md +166 -50
- package/framework/standards/ai-agents/structured-output.md +280 -249
- package/framework/standards/ai-agents/sweet-spot.md +129 -109
- 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 +90 -0
- package/framework/templates/REGISTRY.json +14 -1
- package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +95 -95
- package/framework/templates/code/sql/ai-agents/agent-prompts-migration.sql.template +58 -58
- 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/infrastructure/docker/docker-compose.template.yml +24 -14
- package/package.json +3 -3
- package/src/commands/e2e/e2e.js +91 -40
- package/src/commands/project/doctor.js +143 -6
- package/src/commands/project/env.js +95 -0
- package/src/commands/project/update.js +469 -153
- package/src/commands/project/worktree.js +274 -53
- 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/delete.js +8 -0
- package/src/commands/state/finish.js +360 -53
- 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/state-manager.js +9 -1
- package/src/dashboard/app/pages/HookInspector.jsx +430 -418
- package/src/dashboard/scanner/hooks-scanner.js +5 -1
- 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/e2e/compose-env.js +55 -14
- package/src/lib/e2e/stack-teardown.js +115 -0
- package/src/lib/evaluator-report.js +269 -15
- package/src/lib/generators/architecture-scanner.js +2 -1
- package/src/lib/git/default-branch.js +92 -4
- package/src/lib/graph/graphifyignore.js +2 -1
- package/src/lib/installers/effects.js +193 -0
- 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/test-nodes.js +486 -0
- package/src/lib/tasks/test-runner.js +431 -37
- package/src/lib/validators/verify-runner.js +590 -28
- package/src/lib/worktree/dirs.js +32 -0
- package/src/lib/worktree/docker-audit.js +287 -0
- package/src/lib/worktree/env-allocator.js +69 -11
- package/src/lib/worktree/worktree-audit.js +70 -3
- package/src/scripts/setup-infra.js +24 -11
- package/src/utils/agents-installer.js +18 -8
- package/src/utils/claude-md-injector.js +10 -5
- package/src/utils/file-copier.js +28 -16
- package/src/utils/hooks-installer.js +75 -29
- package/src/utils/skills-installer.js +194 -187
- package/src/utils/version-checker.js +68 -3
- package/framework/standards/ai-agents/prompts-in-db.md +0 -214
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
> **Keywords:** workflow, orchestration, fan-in, fan-out, multi-agent workflow, sequential workflow
|
|
6
6
|
> **Read by Claude in:** plan (only when a genuine fan-in/out or long-running need appears)
|
|
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, Microsoft.Agents.AI.Workflows.Declarative 1.20.0 e Microsoft.Agents.AI.Declarative `1.20.0-rc1` (**os três fora do pin**; versões apuradas no nuget.org em 2026-09-08). **Verificação documental**, sem cláusula `provado por` — o ai-kit não monta workflows. **A localização dos tipos de workflow foi medida por reflexão em 2026-09-08 e CORRIGE este standard**: eles não estão no pacote base. Last-verified: 2026-09-08.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -43,19 +43,39 @@ Para o critério de HITL/long-running acima, a implementação (`RequestPort`, `
|
|
|
43
43
|
|
|
44
44
|
## Packages
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
> **Correção de 2026-09-08, medida.** A versão anterior deste standard dizia que `AgentWorkflowBuilder`, `WorkflowBuilder` e `InProcessExecution` estavam no pacote base `Microsoft.Agents.AI`. **Não estão.** Varredura dos tipos exportados de `Microsoft.Agents.AI` 1.20.0: **zero** tipos de workflow. Todos os 132 tipos de workflow — `AgentWorkflowBuilder`, `WorkflowBuilder`, `InProcessExecution`, `HandoffWorkflowBuilder`, `GroupChatWorkflowBuilder`, `MagenticWorkflowBuilder`, `CheckpointManager` — vivem em **`Microsoft.Agents.AI.Workflows`**, um pacote **separado**. Seguir o texto antigo dá erro de compilação, não aviso.
|
|
47
47
|
|
|
48
48
|
```xml
|
|
49
|
-
|
|
49
|
+
<!-- Base MAF — no ai-pin.json -->
|
|
50
|
+
<PackageReference Include="Microsoft.Agents.AI" Version="1.20.0" />
|
|
51
|
+
|
|
52
|
+
<!-- Workflows: PACOTE SEPARADO. Estável. Fora do pin; apurado no nuget.org em 2026-09-08. -->
|
|
53
|
+
<PackageReference Include="Microsoft.Agents.AI.Workflows" Version="1.20.0" />
|
|
50
54
|
```
|
|
51
55
|
|
|
52
|
-
Para DI helpers (`AddAIAgent`):
|
|
56
|
+
Para DI helpers (`AddAIAgent`, `AddSequentialWorkflow`):
|
|
53
57
|
|
|
54
58
|
```xml
|
|
55
|
-
|
|
59
|
+
<!-- PRERELEASE: não há versão estável. Fora do pin; apurado em 2026-09-08. -->
|
|
60
|
+
<PackageReference Include="Microsoft.Agents.AI.Hosting" Version="1.20.0-preview.260831.1" />
|
|
56
61
|
```
|
|
57
62
|
|
|
58
|
-
|
|
63
|
+
### Declarativo: workflow é estável, agente ainda não
|
|
64
|
+
|
|
65
|
+
Os dois costumam ser citados juntos e têm maturidade **diferente**. Apurado no nuget.org em 2026-09-08:
|
|
66
|
+
|
|
67
|
+
| Pacote | Última versão | Estável? |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| `Microsoft.Agents.AI.Workflows.Declarative` (workflows em YAML) | **1.20.0** | **Sim** — estáveis desde a 1.9 |
|
|
70
|
+
| `Microsoft.Agents.AI.Declarative` (agentes declarativos) | `1.20.0-rc1` | **Não** — ainda exige `--prerelease` |
|
|
71
|
+
|
|
72
|
+
Ou seja: descrever o **grafo** em YAML é caminho estável; descrever o **agente** em YAML ainda não.
|
|
73
|
+
|
|
74
|
+
### Mudança de comportamento na 1.17
|
|
75
|
+
|
|
76
|
+
A partir da **1.17**, um workflow **falha quando um agente participante retorna erro** — antes o erro podia ser absorvido e o grafo seguia com um resultado parcial. Consequência: um workflow que "sempre funcionou" pode passar a falhar depois do upgrade, e isso é o comportamento **correto**. Trate erro de agente explicitamente (branch de erro no grafo, ou tratamento dentro do executor) em vez de contar com a absorção antiga.
|
|
77
|
+
|
|
78
|
+
> Sem `Microsoft.Extensions.AI 9.x`. Nenhuma faixa flutuante — SDK de cadência semanal com `1.0.*` é o defeito que `ai-agents-setup` §1 proíbe.
|
|
59
79
|
|
|
60
80
|
---
|
|
61
81
|
|
|
@@ -187,4 +207,4 @@ Sempre use `await using` no `StreamingRun` / `Run` — é `IAsyncDisposable`.
|
|
|
187
207
|
|
|
188
208
|
---
|
|
189
209
|
|
|
190
|
-
*MORPH-SPEC by Polymorphism Tech — ai-agents/workflows.md v2.0 (2026-
|
|
210
|
+
*MORPH-SPEC by Polymorphism Tech — ai-agents/workflows.md v2.0 (2026-09-08)*
|
|
@@ -288,4 +288,16 @@ If none are good, regenerate at the same step with the prompt adjusted by the fe
|
|
|
288
288
|
- [ ] Images headed for video framed without faces
|
|
289
289
|
- [ ] Favicon and 1200x630 OG image produced
|
|
290
290
|
|
|
291
|
+
## Boundary: Runtime Generation Is Another Standard
|
|
292
|
+
|
|
293
|
+
This standard is **authoring time**: a designer, an MCP tool, and assets that end up committed in the
|
|
294
|
+
repository. When the **product itself** generates images at runtime — a .NET backend calling a paid
|
|
295
|
+
API per request, with cost, review and provenance — the standard is
|
|
296
|
+
`ai-agents/modalities-image-gen.md`, and the surrounding job/review/labelling pipeline is
|
|
297
|
+
`ai-agents/media-pipeline.md`.
|
|
298
|
+
|
|
299
|
+
The two do not overlap: nothing here talks about paid calls per user, and nothing there repeats the
|
|
300
|
+
brand prompt craft above. The rule that never crosses the boundary is the hard one from
|
|
301
|
+
`ai-agents/media-pipeline.md`: **never generate media inside a conversation turn**.
|
|
302
|
+
|
|
291
303
|
*MORPH-SPEC by Polymorphism Tech*
|
|
@@ -110,4 +110,17 @@ TECHNICAL: img2vid with image (start) + endImage (end). No audio. No watermark.
|
|
|
110
110
|
- [ ] Draft at 480p/4s approved before any 1080p render
|
|
111
111
|
- [ ] Frames re-extracted with a bumped cache-bust after the final render
|
|
112
112
|
|
|
113
|
+
## Boundary: Runtime Generation Is Another Standard
|
|
114
|
+
|
|
115
|
+
This standard is **authoring time**: a human driving the seedance MCP in a session, footage that ends
|
|
116
|
+
up committed as a page asset. When the **product itself** generates video at runtime — a .NET worker
|
|
117
|
+
creating a paid task, polling an operation, downloading bytes into its own blob store — the standard
|
|
118
|
+
is `ai-agents/media-video.md` (Veo via `Google.GenAI`, the HTTP-only providers, cost per second, the
|
|
119
|
+
2-day retention), and the surrounding job/review/labelling pipeline is
|
|
120
|
+
`ai-agents/media-pipeline.md`.
|
|
121
|
+
|
|
122
|
+
The face-moderation workaround in Section 3 above is the piece `ai-agents/media-video.md` cites
|
|
123
|
+
rather than repeats. The rule that never crosses the boundary is the hard one from
|
|
124
|
+
`ai-agents/media-pipeline.md`: **never generate media inside a conversation turn**.
|
|
125
|
+
|
|
113
126
|
*MORPH-SPEC by Polymorphism Tech*
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Local Compose Isolation Standard
|
|
2
|
+
|
|
3
|
+
> **Scope:** any stack that runs `docker compose` locally (Next.js + Neon, .NET)
|
|
4
|
+
> **Layer:** 2 (on keyword)
|
|
5
|
+
> **Keywords:** docker compose, worktree, ports, container_name, POSTGRES_PORT, COMPOSE_PROJECT_NAME, local dev, e2e stack
|
|
6
|
+
> **Load When:** a compose file, a dev-server port, or a worktree stack is being written or debugged
|
|
7
|
+
|
|
8
|
+
**Verified against:** Docker Compose v2 + morph-spec 8.34 (dedicated stack per worktree). Last-verified: 2026-09-08.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Why this exists
|
|
13
|
+
|
|
14
|
+
Every feature worktree runs its **own** compose stack — its own project, its own postgres, its own volumes. That only holds if the compose file lets the harness pick the host ports and the project name. A file that hardcodes either one looks isolated and collides the moment a second worktree starts: `container_name` is never prefixed by the project, and a fixed `5432:5432` is one host port for everybody.
|
|
15
|
+
|
|
16
|
+
The harness gives each worktree a **block of 10 ports** (`.morph/worktree.env`, written by `morph-spec worktree setup|provision`, regenerated by `worktree link --all`). The same values reach `docker compose` through the `verify` e2e node, `morph-spec e2e up`, the `PreToolUse:Bash` hook (which prefixes `npm run dev` / `dotnet run` / `docker compose` with them) and `morph-spec env` for a plain shell.
|
|
17
|
+
|
|
18
|
+
## Port layout (one contract, everywhere)
|
|
19
|
+
|
|
20
|
+
| Offset | Variable | Compose mapping |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| +0 | `PORT` | `"${PORT:-3000}:3000"` — web / dev server |
|
|
23
|
+
| +1 | `API_PORT` (and `ASPNETCORE_URLS=http://localhost:<+1>` on .NET) | `"${API_PORT:-5000}:8080"` |
|
|
24
|
+
| +2 | `POSTGRES_PORT` | `"${POSTGRES_PORT:-5432}:5432"` |
|
|
25
|
+
| +3 | `REDIS_PORT` | `"${REDIS_PORT:-6379}:6379"` (reserved) |
|
|
26
|
+
| +4..+9 | free | project-specific services |
|
|
27
|
+
|
|
28
|
+
Also exported: `COMPOSE_PROJECT_NAME=morph-{feature}` (isolates container, network and volume names), `MORPH_PORT_BASE`, `MORPH_PORT_RANGE`, `PLAYWRIGHT_BASE_URL=http://localhost:<+0>`.
|
|
29
|
+
|
|
30
|
+
## Core Rules
|
|
31
|
+
|
|
32
|
+
- NEVER set `container_name` — Compose already names containers `<project>-<service>-1`, and an explicit name is shared by every worktree
|
|
33
|
+
- ALWAYS publish host ports through a variable with a default: `"${PORT:-3000}:3000"`, never `"3000:3000"` nor `published: 3000`
|
|
34
|
+
- ALWAYS keep the database name stable (`POSTGRES_DB: ${POSTGRES_DB:-app}`) — the project name already namespaces the container and the volume; baking a feature name into the DB name outlives the feature that scaffolded it
|
|
35
|
+
- ALWAYS declare a healthcheck on every service — `docker compose up --wait` (what the e2e node runs) is meaningless without one
|
|
36
|
+
- ALWAYS give `DATABASE_URL` an in-network default so the stack comes up with no `.env`: `postgresql://postgres:postgres@postgres:5432/${POSTGRES_DB:-app}`
|
|
37
|
+
- ALWAYS read the base URL from the environment in `playwright.config.ts`: `process.env.PLAYWRIGHT_BASE_URL ?? \`http://localhost:${process.env.PORT ?? 3000}\``
|
|
38
|
+
- NEVER put a cloud connection string (Neon branch etc.) in `.morph/worktree.env` — it is regenerated; credentials go in the gitignored file named by `config.json → e2e.auth.envFile`
|
|
39
|
+
- NEVER put a variable from the port layout table above (nor `PLAYWRIGHT_BASE_URL`) in that credentials file — the harness **ignores** it and says which key it ignored on stderr. Ports come from the allocated block; the file carries credentials. A `.env.e2e` copied from a sibling worktree carries THAT worktree's block, and before the filter existed it silently repointed this stack at the neighbour's postgres
|
|
40
|
+
|
|
41
|
+
## What the harness enforces
|
|
42
|
+
|
|
43
|
+
- Inside a secondary worktree, a compose with a fixed host port or a `container_name` **fails the `verify` e2e node** (`compose-not-isolable`) — Gate 3 cannot pass on a stack that cannot run beside its siblings. At the primary root the same finding is a warning.
|
|
44
|
+
- `morph-spec finish` tears the stack down **with volumes** (`--keep-volumes` opts out) and deletes the freshness stamp; `morph-spec worktree remove` tears it down without volumes (the feature is still open).
|
|
45
|
+
- Two worktrees never share `POSTGRES_PORT`: the block is allocated first-free-index per feature and released only when the worktree is removed.
|
|
46
|
+
- The credentials env file is read **after** the block but cannot outrank it. All four surfaces (`e2e up`, the `verify` e2e node, the teardown, `morph-spec env`) build their environment through the same `buildComposeEnv`, which drops the layout keys coming from that file and names them on **stderr** — stdout stays eval-safe for `eval "$(morph-spec env)"`. With no block allocated (outside a worktree) nothing is filtered: there the file is the only port source.
|
|
47
|
+
|
|
48
|
+
## Minimal compose skeleton
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
services:
|
|
52
|
+
app:
|
|
53
|
+
build: { context: ., dockerfile: Dockerfile.dev }
|
|
54
|
+
ports:
|
|
55
|
+
- "${PORT:-3000}:3000"
|
|
56
|
+
environment:
|
|
57
|
+
- DATABASE_URL=${DATABASE_URL:-postgresql://postgres:postgres@postgres:5432/${POSTGRES_DB:-app}}
|
|
58
|
+
depends_on:
|
|
59
|
+
postgres: { condition: service_healthy }
|
|
60
|
+
healthcheck:
|
|
61
|
+
test: ["CMD-SHELL", "node -e \"fetch('http://localhost:3000/').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
|
|
62
|
+
interval: 10s
|
|
63
|
+
timeout: 5s
|
|
64
|
+
retries: 12
|
|
65
|
+
postgres:
|
|
66
|
+
image: postgres:15-alpine
|
|
67
|
+
ports:
|
|
68
|
+
- "${POSTGRES_PORT:-5432}:5432"
|
|
69
|
+
environment:
|
|
70
|
+
POSTGRES_USER: postgres
|
|
71
|
+
POSTGRES_PASSWORD: postgres
|
|
72
|
+
POSTGRES_DB: ${POSTGRES_DB:-app}
|
|
73
|
+
volumes:
|
|
74
|
+
- postgres-data:/var/lib/postgresql/data
|
|
75
|
+
healthcheck:
|
|
76
|
+
test: ["CMD-SHELL", "pg_isready -U postgres -d ${POSTGRES_DB:-app}"]
|
|
77
|
+
interval: 5s
|
|
78
|
+
timeout: 5s
|
|
79
|
+
retries: 10
|
|
80
|
+
volumes:
|
|
81
|
+
postgres-data:
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Running it by hand
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# inside the worktree, outside Claude Code
|
|
88
|
+
eval "$(morph-spec env)" # PowerShell: morph-spec env --powershell | Invoke-Expression
|
|
89
|
+
docker compose up -d --wait # lands in project morph-{feature}, on the block's ports
|
|
90
|
+
```
|
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
"description": "Template Registry for MORPH-SPEC Framework - Technology-based organization for multi-stack reusability",
|
|
5
5
|
"lastUpdated": "2026-02-27",
|
|
6
6
|
"migration": "v1 → v2: Migrated all templates to framework/, organized by technology (code/dotnet/, infrastructure/azure/, etc.) instead of by stack. This enables future stacks (vue-firebase, angular-mongodb) to reuse existing technology templates.",
|
|
7
|
+
"kinds": {
|
|
8
|
+
"template": "Rendered to an output file. Rich shape: id, name, path, category, phase, outputName (+ engine, placeholders).",
|
|
9
|
+
"fragment": "A reference snippet read as an example, never rendered. Minimal shape: id, path, category, stack, description.",
|
|
10
|
+
"project": "A whole compilable project registered as ONE unit — its files are not consumable one by one. Minimal shape: id, path, category, stack, description; `path` ends in \"/\" because it is a DIRECTORY. Every tracked file under it counts as registered (validate-framework.js Check 12), and a project directory with no tracked file is an error."
|
|
11
|
+
},
|
|
7
12
|
"categories": [
|
|
8
13
|
"documentation",
|
|
9
14
|
"code",
|
|
@@ -468,7 +473,7 @@
|
|
|
468
473
|
"category": "infrastructure",
|
|
469
474
|
"phase": "implement",
|
|
470
475
|
"required": false,
|
|
471
|
-
"description": "Docker Compose for local development
|
|
476
|
+
"description": "Docker Compose for local development — one isolated stack per worktree (ports from the block, no container_name)",
|
|
472
477
|
"outputName": "docker-compose.yml",
|
|
473
478
|
"placeholders": [],
|
|
474
479
|
"stackSpecific": false,
|
|
@@ -1243,6 +1248,14 @@
|
|
|
1243
1248
|
"stack": "dotnet",
|
|
1244
1249
|
"description": "Typed MAF tool retrieving relevant chunks from the pgvector knowledge base"
|
|
1245
1250
|
},
|
|
1251
|
+
{
|
|
1252
|
+
"id": "ai-kit",
|
|
1253
|
+
"kind": "project",
|
|
1254
|
+
"path": "dotnet/ai-kit/",
|
|
1255
|
+
"category": "ai-agents",
|
|
1256
|
+
"stack": "dotnet",
|
|
1257
|
+
"description": "Morph.AiKit — solucao .NET compilavel que prova os standards ai-agents contra framework/ai-pin.json"
|
|
1258
|
+
},
|
|
1246
1259
|
{
|
|
1247
1260
|
"id": "maf-model-registry-config",
|
|
1248
1261
|
"kind": "fragment",
|
|
@@ -1,95 +1,95 @@
|
|
|
1
|
-
// TEMPLATE: PromptRepository.cs
|
|
2
|
-
// PURPOSE: Loads agent system prompts from the agent_prompts table, with in-memory caching.
|
|
3
|
-
// READS STANDARD: ai-agents-
|
|
4
|
-
// PLACEHOLDERS:
|
|
5
|
-
// {{PROJECT_NAMESPACE}} — root namespace of the project
|
|
6
|
-
// LAST-VERIFIED: 2026-05-19
|
|
7
|
-
|
|
8
|
-
using Microsoft.EntityFrameworkCore;
|
|
9
|
-
using Microsoft.Extensions.Caching.Memory;
|
|
10
|
-
|
|
11
|
-
namespace {{PROJECT_NAMESPACE}}.AI;
|
|
12
|
-
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
|
-
// Entity — map this to the agent_prompts table (EF Core convention mapping).
|
|
15
|
-
// Alternatively, configure via Fluent API in your DbContext.OnModelCreating.
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
|
-
|
|
18
|
-
/// <summary>
|
|
19
|
-
/// EF Core entity for the agent_prompts table.
|
|
20
|
-
/// Content is immutable once written — use INSERT + flip is_active for versioning.
|
|
21
|
-
/// </summary>
|
|
22
|
-
public sealed class AgentPrompt
|
|
23
|
-
{
|
|
24
|
-
public Guid Id { get; init; } = Guid.CreateVersion7();
|
|
25
|
-
public required string AgentKey { get; init; }
|
|
26
|
-
public int Version { get; init; }
|
|
27
|
-
public required string Content { get; init; }
|
|
28
|
-
public bool IsActive { get; set; }
|
|
29
|
-
public DateTimeOffset CreatedAt { get; init; } = DateTimeOffset.UtcNow;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// ---------------------------------------------------------------------------
|
|
33
|
-
// Interface
|
|
34
|
-
// ---------------------------------------------------------------------------
|
|
35
|
-
|
|
36
|
-
/// <summary>
|
|
37
|
-
/// Provides the active system-prompt content for a named agent.
|
|
38
|
-
/// </summary>
|
|
39
|
-
public interface IPromptRepository
|
|
40
|
-
{
|
|
41
|
-
/// <summary>
|
|
42
|
-
/// Returns the content of the currently active prompt for <paramref name="agentKey"/>.
|
|
43
|
-
/// </summary>
|
|
44
|
-
/// <exception cref="InvalidOperationException">
|
|
45
|
-
/// Thrown when no row with <c>is_active = true</c> exists for <paramref name="agentKey"/>.
|
|
46
|
-
/// </exception>
|
|
47
|
-
Task<string> GetActivePromptAsync(string agentKey, CancellationToken ct = default);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// ---------------------------------------------------------------------------
|
|
51
|
-
// Implementation
|
|
52
|
-
// ---------------------------------------------------------------------------
|
|
53
|
-
|
|
54
|
-
// NOTE: Register in Program.cs (or a bootstrap extension):
|
|
55
|
-
// builder.Services.AddMemoryCache();
|
|
56
|
-
// builder.Services.AddScoped<IPromptRepository, PromptRepository>();
|
|
57
|
-
//
|
|
58
|
-
// The DbContext must expose: public DbSet<AgentPrompt> AgentPrompts { get; set; }
|
|
59
|
-
// Replace YourDbContext below with the actual DbContext type of the project.
|
|
60
|
-
|
|
61
|
-
/// <summary>
|
|
62
|
-
/// Reads the active agent prompt from the database with an in-memory cache
|
|
63
|
-
/// (default TTL: 5 minutes sliding). Cache invalidation is time-based;
|
|
64
|
-
/// for immediate invalidation after a prompt update call
|
|
65
|
-
/// <c>IMemoryCache.Remove($"agent_prompt:{agentKey}")</c>.
|
|
66
|
-
/// </summary>
|
|
67
|
-
public sealed class PromptRepository(YourDbContext db, IMemoryCache cache) : IPromptRepository
|
|
68
|
-
{
|
|
69
|
-
private static readonly TimeSpan CacheTtl = TimeSpan.FromMinutes(5);
|
|
70
|
-
|
|
71
|
-
public async Task<string> GetActivePromptAsync(string agentKey, CancellationToken ct = default)
|
|
72
|
-
{
|
|
73
|
-
var cacheKey = $"agent_prompt:{agentKey}";
|
|
74
|
-
|
|
75
|
-
if (cache.TryGetValue(cacheKey, out string? cached) && cached is not null)
|
|
76
|
-
return cached;
|
|
77
|
-
|
|
78
|
-
var content = await db.AgentPrompts
|
|
79
|
-
.Where(p => p.AgentKey == agentKey && p.IsActive)
|
|
80
|
-
.Select(p => p.Content)
|
|
81
|
-
.FirstOrDefaultAsync(ct);
|
|
82
|
-
|
|
83
|
-
if (content is null)
|
|
84
|
-
throw new InvalidOperationException(
|
|
85
|
-
$"No active prompt found for agent '{agentKey}'. " +
|
|
86
|
-
"Insert a row in agent_prompts with is_active = true for this agent_key.");
|
|
87
|
-
|
|
88
|
-
cache.Set(cacheKey, content, new MemoryCacheEntryOptions
|
|
89
|
-
{
|
|
90
|
-
SlidingExpiration = CacheTtl
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
return content;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
1
|
+
// TEMPLATE: PromptRepository.cs
|
|
2
|
+
// PURPOSE: Loads agent system prompts from the agent_prompts table, with in-memory caching.
|
|
3
|
+
// READS STANDARD: ai-agents-prompt-sources
|
|
4
|
+
// PLACEHOLDERS:
|
|
5
|
+
// {{PROJECT_NAMESPACE}} — root namespace of the project
|
|
6
|
+
// LAST-VERIFIED: 2026-05-19
|
|
7
|
+
|
|
8
|
+
using Microsoft.EntityFrameworkCore;
|
|
9
|
+
using Microsoft.Extensions.Caching.Memory;
|
|
10
|
+
|
|
11
|
+
namespace {{PROJECT_NAMESPACE}}.AI;
|
|
12
|
+
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Entity — map this to the agent_prompts table (EF Core convention mapping).
|
|
15
|
+
// Alternatively, configure via Fluent API in your DbContext.OnModelCreating.
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
/// <summary>
|
|
19
|
+
/// EF Core entity for the agent_prompts table.
|
|
20
|
+
/// Content is immutable once written — use INSERT + flip is_active for versioning.
|
|
21
|
+
/// </summary>
|
|
22
|
+
public sealed class AgentPrompt
|
|
23
|
+
{
|
|
24
|
+
public Guid Id { get; init; } = Guid.CreateVersion7();
|
|
25
|
+
public required string AgentKey { get; init; }
|
|
26
|
+
public int Version { get; init; }
|
|
27
|
+
public required string Content { get; init; }
|
|
28
|
+
public bool IsActive { get; set; }
|
|
29
|
+
public DateTimeOffset CreatedAt { get; init; } = DateTimeOffset.UtcNow;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Interface
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
/// <summary>
|
|
37
|
+
/// Provides the active system-prompt content for a named agent.
|
|
38
|
+
/// </summary>
|
|
39
|
+
public interface IPromptRepository
|
|
40
|
+
{
|
|
41
|
+
/// <summary>
|
|
42
|
+
/// Returns the content of the currently active prompt for <paramref name="agentKey"/>.
|
|
43
|
+
/// </summary>
|
|
44
|
+
/// <exception cref="InvalidOperationException">
|
|
45
|
+
/// Thrown when no row with <c>is_active = true</c> exists for <paramref name="agentKey"/>.
|
|
46
|
+
/// </exception>
|
|
47
|
+
Task<string> GetActivePromptAsync(string agentKey, CancellationToken ct = default);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// Implementation
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
// NOTE: Register in Program.cs (or a bootstrap extension):
|
|
55
|
+
// builder.Services.AddMemoryCache();
|
|
56
|
+
// builder.Services.AddScoped<IPromptRepository, PromptRepository>();
|
|
57
|
+
//
|
|
58
|
+
// The DbContext must expose: public DbSet<AgentPrompt> AgentPrompts { get; set; }
|
|
59
|
+
// Replace YourDbContext below with the actual DbContext type of the project.
|
|
60
|
+
|
|
61
|
+
/// <summary>
|
|
62
|
+
/// Reads the active agent prompt from the database with an in-memory cache
|
|
63
|
+
/// (default TTL: 5 minutes sliding). Cache invalidation is time-based;
|
|
64
|
+
/// for immediate invalidation after a prompt update call
|
|
65
|
+
/// <c>IMemoryCache.Remove($"agent_prompt:{agentKey}")</c>.
|
|
66
|
+
/// </summary>
|
|
67
|
+
public sealed class PromptRepository(YourDbContext db, IMemoryCache cache) : IPromptRepository
|
|
68
|
+
{
|
|
69
|
+
private static readonly TimeSpan CacheTtl = TimeSpan.FromMinutes(5);
|
|
70
|
+
|
|
71
|
+
public async Task<string> GetActivePromptAsync(string agentKey, CancellationToken ct = default)
|
|
72
|
+
{
|
|
73
|
+
var cacheKey = $"agent_prompt:{agentKey}";
|
|
74
|
+
|
|
75
|
+
if (cache.TryGetValue(cacheKey, out string? cached) && cached is not null)
|
|
76
|
+
return cached;
|
|
77
|
+
|
|
78
|
+
var content = await db.AgentPrompts
|
|
79
|
+
.Where(p => p.AgentKey == agentKey && p.IsActive)
|
|
80
|
+
.Select(p => p.Content)
|
|
81
|
+
.FirstOrDefaultAsync(ct);
|
|
82
|
+
|
|
83
|
+
if (content is null)
|
|
84
|
+
throw new InvalidOperationException(
|
|
85
|
+
$"No active prompt found for agent '{agentKey}'. " +
|
|
86
|
+
"Insert a row in agent_prompts with is_active = true for this agent_key.");
|
|
87
|
+
|
|
88
|
+
cache.Set(cacheKey, content, new MemoryCacheEntryOptions
|
|
89
|
+
{
|
|
90
|
+
SlidingExpiration = CacheTtl
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return content;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -1,58 +1,58 @@
|
|
|
1
|
-
-- TEMPLATE: agent-prompts-migration.sql
|
|
2
|
-
-- PURPOSE: Creates the agent_prompts table for runtime-editable, versioned agent instructions.
|
|
3
|
-
-- READS STANDARD: ai-agents-
|
|
4
|
-
-- PLACEHOLDERS:
|
|
5
|
-
-- {{SCHEMA}} — target schema (default: public)
|
|
6
|
-
-- LAST-VERIFIED: 2026-05-19
|
|
7
|
-
|
|
8
|
-
-- ============================================================
|
|
9
|
-
-- 1. TABLE
|
|
10
|
-
-- ============================================================
|
|
11
|
-
|
|
12
|
-
CREATE TABLE {{SCHEMA}}.agent_prompts (
|
|
13
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
14
|
-
agent_key text NOT NULL,
|
|
15
|
-
version int NOT NULL,
|
|
16
|
-
content text NOT NULL,
|
|
17
|
-
is_active boolean NOT NULL DEFAULT false,
|
|
18
|
-
created_at timestamptz NOT NULL DEFAULT now()
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
COMMENT ON TABLE {{SCHEMA}}.agent_prompts IS 'Runtime-editable, versioned system prompts for AI agents.';
|
|
22
|
-
COMMENT ON COLUMN {{SCHEMA}}.agent_prompts.agent_key IS 'Logical identifier for the agent (e.g. ''proposal-agent'').';
|
|
23
|
-
COMMENT ON COLUMN {{SCHEMA}}.agent_prompts.version IS 'Monotonically increasing per agent_key. Never reuse a version number.';
|
|
24
|
-
COMMENT ON COLUMN {{SCHEMA}}.agent_prompts.content IS 'Immutable system-prompt text. UPDATE of this column is forbidden — insert a new row instead.';
|
|
25
|
-
COMMENT ON COLUMN {{SCHEMA}}.agent_prompts.is_active IS 'Exactly one row per agent_key may have is_active = true (enforced by ix_agent_prompts_active).';
|
|
26
|
-
COMMENT ON COLUMN {{SCHEMA}}.agent_prompts.created_at IS 'Audit timestamp. Set at insert time, never updated.';
|
|
27
|
-
|
|
28
|
-
-- ============================================================
|
|
29
|
-
-- 2. INDEXES
|
|
30
|
-
-- ============================================================
|
|
31
|
-
|
|
32
|
-
-- Unique partial index: enforces at DB level that only one active prompt
|
|
33
|
-
-- exists per agent_key. Any attempt to INSERT a second active row for the
|
|
34
|
-
-- same key will fail with a unique-constraint violation.
|
|
35
|
-
CREATE UNIQUE INDEX ix_agent_prompts_active
|
|
36
|
-
ON {{SCHEMA}}.agent_prompts (agent_key)
|
|
37
|
-
WHERE is_active;
|
|
38
|
-
|
|
39
|
-
-- Regular index for the PromptRepository lookup (agent_key + is_active filter).
|
|
40
|
-
CREATE INDEX ix_agent_prompts_agent_key
|
|
41
|
-
ON {{SCHEMA}}.agent_prompts (agent_key);
|
|
42
|
-
|
|
43
|
-
-- Unique index: prevents duplicate version numbers per agent_key.
|
|
44
|
-
CREATE UNIQUE INDEX ix_agent_prompts_agent_key_version
|
|
45
|
-
ON {{SCHEMA}}.agent_prompts (agent_key, version);
|
|
46
|
-
|
|
47
|
-
-- ============================================================
|
|
48
|
-
-- 3. SEED (optional — remove if managed via backoffice)
|
|
49
|
-
-- ============================================================
|
|
50
|
-
|
|
51
|
-
-- INSERT INTO {{SCHEMA}}.agent_prompts (agent_key, version, content, is_active)
|
|
52
|
-
-- VALUES ('my-agent', 1, 'You are a helpful assistant.', true);
|
|
53
|
-
|
|
54
|
-
-- ============================================================
|
|
55
|
-
-- ROLLBACK
|
|
56
|
-
-- ============================================================
|
|
57
|
-
|
|
58
|
-
-- DROP TABLE IF EXISTS {{SCHEMA}}.agent_prompts CASCADE;
|
|
1
|
+
-- TEMPLATE: agent-prompts-migration.sql
|
|
2
|
+
-- PURPOSE: Creates the agent_prompts table for runtime-editable, versioned agent instructions.
|
|
3
|
+
-- READS STANDARD: ai-agents-prompt-sources
|
|
4
|
+
-- PLACEHOLDERS:
|
|
5
|
+
-- {{SCHEMA}} — target schema (default: public)
|
|
6
|
+
-- LAST-VERIFIED: 2026-05-19
|
|
7
|
+
|
|
8
|
+
-- ============================================================
|
|
9
|
+
-- 1. TABLE
|
|
10
|
+
-- ============================================================
|
|
11
|
+
|
|
12
|
+
CREATE TABLE {{SCHEMA}}.agent_prompts (
|
|
13
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
14
|
+
agent_key text NOT NULL,
|
|
15
|
+
version int NOT NULL,
|
|
16
|
+
content text NOT NULL,
|
|
17
|
+
is_active boolean NOT NULL DEFAULT false,
|
|
18
|
+
created_at timestamptz NOT NULL DEFAULT now()
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
COMMENT ON TABLE {{SCHEMA}}.agent_prompts IS 'Runtime-editable, versioned system prompts for AI agents.';
|
|
22
|
+
COMMENT ON COLUMN {{SCHEMA}}.agent_prompts.agent_key IS 'Logical identifier for the agent (e.g. ''proposal-agent'').';
|
|
23
|
+
COMMENT ON COLUMN {{SCHEMA}}.agent_prompts.version IS 'Monotonically increasing per agent_key. Never reuse a version number.';
|
|
24
|
+
COMMENT ON COLUMN {{SCHEMA}}.agent_prompts.content IS 'Immutable system-prompt text. UPDATE of this column is forbidden — insert a new row instead.';
|
|
25
|
+
COMMENT ON COLUMN {{SCHEMA}}.agent_prompts.is_active IS 'Exactly one row per agent_key may have is_active = true (enforced by ix_agent_prompts_active).';
|
|
26
|
+
COMMENT ON COLUMN {{SCHEMA}}.agent_prompts.created_at IS 'Audit timestamp. Set at insert time, never updated.';
|
|
27
|
+
|
|
28
|
+
-- ============================================================
|
|
29
|
+
-- 2. INDEXES
|
|
30
|
+
-- ============================================================
|
|
31
|
+
|
|
32
|
+
-- Unique partial index: enforces at DB level that only one active prompt
|
|
33
|
+
-- exists per agent_key. Any attempt to INSERT a second active row for the
|
|
34
|
+
-- same key will fail with a unique-constraint violation.
|
|
35
|
+
CREATE UNIQUE INDEX ix_agent_prompts_active
|
|
36
|
+
ON {{SCHEMA}}.agent_prompts (agent_key)
|
|
37
|
+
WHERE is_active;
|
|
38
|
+
|
|
39
|
+
-- Regular index for the PromptRepository lookup (agent_key + is_active filter).
|
|
40
|
+
CREATE INDEX ix_agent_prompts_agent_key
|
|
41
|
+
ON {{SCHEMA}}.agent_prompts (agent_key);
|
|
42
|
+
|
|
43
|
+
-- Unique index: prevents duplicate version numbers per agent_key.
|
|
44
|
+
CREATE UNIQUE INDEX ix_agent_prompts_agent_key_version
|
|
45
|
+
ON {{SCHEMA}}.agent_prompts (agent_key, version);
|
|
46
|
+
|
|
47
|
+
-- ============================================================
|
|
48
|
+
-- 3. SEED (optional — remove if managed via backoffice)
|
|
49
|
+
-- ============================================================
|
|
50
|
+
|
|
51
|
+
-- INSERT INTO {{SCHEMA}}.agent_prompts (agent_key, version, content, is_active)
|
|
52
|
+
-- VALUES ('my-agent', 1, 'You are a helpful assistant.', true);
|
|
53
|
+
|
|
54
|
+
-- ============================================================
|
|
55
|
+
-- ROLLBACK
|
|
56
|
+
-- ============================================================
|
|
57
|
+
|
|
58
|
+
-- DROP TABLE IF EXISTS {{SCHEMA}}.agent_prompts CASCADE;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<Project>
|
|
2
|
+
|
|
3
|
+
<!--
|
|
4
|
+
Propriedades comuns a TODOS os projetos do Morph.AiKit.
|
|
5
|
+
|
|
6
|
+
NAO escreva versao de pacote aqui nem em nenhum .csproj: as versoes vivem em
|
|
7
|
+
Directory.Packages.props, GERADO por scripts/generate-ai-pin-props.js a partir de
|
|
8
|
+
framework/ai-pin.json. Com Central Package Management ligado, um <PackageReference>
|
|
9
|
+
com atributo Version vira erro de restore (NU1008) — e por isso que um .csproj nao
|
|
10
|
+
consegue divergir do pin.
|
|
11
|
+
-->
|
|
12
|
+
<PropertyGroup>
|
|
13
|
+
<TargetFramework>net10.0</TargetFramework>
|
|
14
|
+
<LangVersion>latest</LangVersion>
|
|
15
|
+
<Nullable>enable</Nullable>
|
|
16
|
+
<ImplicitUsings>enable</ImplicitUsings>
|
|
17
|
+
|
|
18
|
+
<!-- Um kit cujo proposito e gritar nao pode engolir warning. -->
|
|
19
|
+
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
|
20
|
+
|
|
21
|
+
<Deterministic>true</Deterministic>
|
|
22
|
+
<IsPackable>false</IsPackable>
|
|
23
|
+
</PropertyGroup>
|
|
24
|
+
|
|
25
|
+
</Project>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<Project>
|
|
2
|
+
<!-- GERADO por scripts/generate-ai-pin-props.js a partir de framework/ai-pin.json. Não editar à mão — mexer no pin é mexer em framework/ai-pin.json. -->
|
|
3
|
+
<!-- pinnedAt: 2026-09-08 · fonte: https://api.nuget.org/v3/registration5-semver1/{id}/index.json -->
|
|
4
|
+
<PropertyGroup>
|
|
5
|
+
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
|
6
|
+
</PropertyGroup>
|
|
7
|
+
|
|
8
|
+
<!-- Pacotes de IA (framework/ai-pin.json → packages) -->
|
|
9
|
+
<ItemGroup>
|
|
10
|
+
<PackageVersion Include="Microsoft.Agents.AI" Version="1.20.0" />
|
|
11
|
+
<PackageVersion Include="Microsoft.Extensions.AI" Version="10.9.0" />
|
|
12
|
+
<PackageVersion Include="OpenAI" Version="2.13.0" />
|
|
13
|
+
<PackageVersion Include="Google.GenAI" Version="1.21.0" />
|
|
14
|
+
<PackageVersion Include="ModelContextProtocol" Version="2.2.0" />
|
|
15
|
+
<PackageVersion Include="Microsoft.Extensions.AI.Evaluation" Version="10.9.0" />
|
|
16
|
+
<PackageVersion Include="Microsoft.Extensions.AI.Evaluation.Quality" Version="10.9.0" />
|
|
17
|
+
<PackageVersion Include="Microsoft.Extensions.AI.Evaluation.Reporting" Version="10.9.0" />
|
|
18
|
+
</ItemGroup>
|
|
19
|
+
|
|
20
|
+
<!-- Build e teste (framework/ai-pin.json → toolchain) -->
|
|
21
|
+
<ItemGroup>
|
|
22
|
+
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.9.0" />
|
|
23
|
+
<PackageVersion Include="xunit.v3" Version="4.0.0" />
|
|
24
|
+
<PackageVersion Include="xunit.runner.visualstudio" Version="4.0.0" />
|
|
25
|
+
</ItemGroup>
|
|
26
|
+
</Project>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
|
|
2
|
+
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
3
|
+
# Visual Studio Version 17
|
|
4
|
+
VisualStudioVersion = 17.0.31903.59
|
|
5
|
+
MinimumVisualStudioVersion = 10.0.40219.1
|
|
6
|
+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
|
|
7
|
+
EndProject
|
|
8
|
+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Morph.AiKit", "src\Morph.AiKit\Morph.AiKit.csproj", "{0577D911-1F1E-422E-A1CD-23379F308B05}"
|
|
9
|
+
EndProject
|
|
10
|
+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0AB3BF05-4346-4AA6-1389-037BE0695223}"
|
|
11
|
+
EndProject
|
|
12
|
+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Morph.AiKit.Tests", "tests\Morph.AiKit.Tests\Morph.AiKit.Tests.csproj", "{A0543CA3-CC90-45F6-940E-3F58570BB4D3}"
|
|
13
|
+
EndProject
|
|
14
|
+
Global
|
|
15
|
+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
16
|
+
Debug|Any CPU = Debug|Any CPU
|
|
17
|
+
Debug|x64 = Debug|x64
|
|
18
|
+
Debug|x86 = Debug|x86
|
|
19
|
+
Release|Any CPU = Release|Any CPU
|
|
20
|
+
Release|x64 = Release|x64
|
|
21
|
+
Release|x86 = Release|x86
|
|
22
|
+
EndGlobalSection
|
|
23
|
+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
24
|
+
{0577D911-1F1E-422E-A1CD-23379F308B05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
25
|
+
{0577D911-1F1E-422E-A1CD-23379F308B05}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
26
|
+
{0577D911-1F1E-422E-A1CD-23379F308B05}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
27
|
+
{0577D911-1F1E-422E-A1CD-23379F308B05}.Debug|x64.Build.0 = Debug|Any CPU
|
|
28
|
+
{0577D911-1F1E-422E-A1CD-23379F308B05}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
29
|
+
{0577D911-1F1E-422E-A1CD-23379F308B05}.Debug|x86.Build.0 = Debug|Any CPU
|
|
30
|
+
{0577D911-1F1E-422E-A1CD-23379F308B05}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
31
|
+
{0577D911-1F1E-422E-A1CD-23379F308B05}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
32
|
+
{0577D911-1F1E-422E-A1CD-23379F308B05}.Release|x64.ActiveCfg = Release|Any CPU
|
|
33
|
+
{0577D911-1F1E-422E-A1CD-23379F308B05}.Release|x64.Build.0 = Release|Any CPU
|
|
34
|
+
{0577D911-1F1E-422E-A1CD-23379F308B05}.Release|x86.ActiveCfg = Release|Any CPU
|
|
35
|
+
{0577D911-1F1E-422E-A1CD-23379F308B05}.Release|x86.Build.0 = Release|Any CPU
|
|
36
|
+
{A0543CA3-CC90-45F6-940E-3F58570BB4D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
37
|
+
{A0543CA3-CC90-45F6-940E-3F58570BB4D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
38
|
+
{A0543CA3-CC90-45F6-940E-3F58570BB4D3}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
39
|
+
{A0543CA3-CC90-45F6-940E-3F58570BB4D3}.Debug|x64.Build.0 = Debug|Any CPU
|
|
40
|
+
{A0543CA3-CC90-45F6-940E-3F58570BB4D3}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
41
|
+
{A0543CA3-CC90-45F6-940E-3F58570BB4D3}.Debug|x86.Build.0 = Debug|Any CPU
|
|
42
|
+
{A0543CA3-CC90-45F6-940E-3F58570BB4D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
43
|
+
{A0543CA3-CC90-45F6-940E-3F58570BB4D3}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
44
|
+
{A0543CA3-CC90-45F6-940E-3F58570BB4D3}.Release|x64.ActiveCfg = Release|Any CPU
|
|
45
|
+
{A0543CA3-CC90-45F6-940E-3F58570BB4D3}.Release|x64.Build.0 = Release|Any CPU
|
|
46
|
+
{A0543CA3-CC90-45F6-940E-3F58570BB4D3}.Release|x86.ActiveCfg = Release|Any CPU
|
|
47
|
+
{A0543CA3-CC90-45F6-940E-3F58570BB4D3}.Release|x86.Build.0 = Release|Any CPU
|
|
48
|
+
EndGlobalSection
|
|
49
|
+
GlobalSection(SolutionProperties) = preSolution
|
|
50
|
+
HideSolutionNode = FALSE
|
|
51
|
+
EndGlobalSection
|
|
52
|
+
GlobalSection(NestedProjects) = preSolution
|
|
53
|
+
{0577D911-1F1E-422E-A1CD-23379F308B05} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
|
|
54
|
+
{A0543CA3-CC90-45F6-940E-3F58570BB4D3} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
|
55
|
+
EndGlobalSection
|
|
56
|
+
EndGlobal
|