@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
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
namespace Morph.AiKit.Media;
|
|
2
|
+
|
|
3
|
+
/// <summary>
|
|
4
|
+
/// A resolucao de um alias de midia: para quem ir, com que modelo, por qual tarifa.
|
|
5
|
+
/// </summary>
|
|
6
|
+
/// <remarks>
|
|
7
|
+
/// O pedido cita o <b>alias</b>; a chave de idempotencia e a proveniencia citam o
|
|
8
|
+
/// <b>modelo</b>. A diferenca importa: um alias pode ser repontado para outro modelo, e
|
|
9
|
+
/// duas geracoes com o mesmo alias e modelos diferentes nao sao o mesmo pedido.
|
|
10
|
+
/// </remarks>
|
|
11
|
+
/// <param name="Alias">O apelido citado pelo pedido.</param>
|
|
12
|
+
/// <param name="Provider">Familia do SDK.</param>
|
|
13
|
+
/// <param name="Model">O id do modelo no provider.</param>
|
|
14
|
+
/// <param name="Kind">Imagem ou video.</param>
|
|
15
|
+
/// <param name="Pricing">A tarifa, na unidade certa. Ver <see cref="MediaPricing"/>.</param>
|
|
16
|
+
public sealed record MediaAliasBinding(
|
|
17
|
+
string Alias,
|
|
18
|
+
string Provider,
|
|
19
|
+
string Model,
|
|
20
|
+
MediaKind Kind,
|
|
21
|
+
MediaPricing Pricing);
|
|
22
|
+
|
|
23
|
+
/// <summary>Resolve um alias de midia. Alias desconhecido e recusa nomeada, nunca nulo.</summary>
|
|
24
|
+
public interface IMediaAliasResolver
|
|
25
|
+
{
|
|
26
|
+
/// <summary>O binding do alias.</summary>
|
|
27
|
+
MediaResult<MediaAliasBinding> Resolve(string alias);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/// <summary>
|
|
31
|
+
/// Onde os jobs ficam guardados. <b>A costura entre o kit e o banco do projeto.</b>
|
|
32
|
+
/// </summary>
|
|
33
|
+
/// <remarks>
|
|
34
|
+
/// Sem tipo de infraestrutura na assinatura, pela mesma razao de
|
|
35
|
+
/// <c>IConversationStore</c>: o kit nao conhece banco. No projeto, o handler fala com o
|
|
36
|
+
/// <c>ApplicationDbContext</c> direto — sem camada de service, sem repository generico.
|
|
37
|
+
/// Dentro de um job, <c>IDbContextFactory</c>, como o standard de Hangfire ja exige.
|
|
38
|
+
/// </remarks>
|
|
39
|
+
public interface IMediaJobRepository
|
|
40
|
+
{
|
|
41
|
+
/// <summary>
|
|
42
|
+
/// O job de mesma chave de PEDIDO, se existir. <b>E a consulta que evita pagar duas
|
|
43
|
+
/// vezes</b>, e por isso ela vem antes de qualquer chamada ao provider.
|
|
44
|
+
/// </summary>
|
|
45
|
+
ValueTask<MediaJob?> FindByIdempotencyKeyAsync(MediaIdempotencyKey key, CancellationToken cancellationToken);
|
|
46
|
+
|
|
47
|
+
/// <summary>O job por id, ou nulo.</summary>
|
|
48
|
+
ValueTask<MediaJob?> FindAsync(MediaJobId id, CancellationToken cancellationToken);
|
|
49
|
+
|
|
50
|
+
/// <summary>Grava o estado corrente do job.</summary>
|
|
51
|
+
ValueTask SaveAsync(MediaJob job, CancellationToken cancellationToken);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/// <summary>
|
|
55
|
+
/// O teto de custo por tenant/dia.
|
|
56
|
+
/// </summary>
|
|
57
|
+
/// <remarks>
|
|
58
|
+
/// <b>A reserva acontece no ENQUEUE</b>, com o custo estimado ANTES da chamada. Um alerta
|
|
59
|
+
/// que chega depois da chamada e contabilidade, nao controle: o dinheiro ja saiu.
|
|
60
|
+
/// </remarks>
|
|
61
|
+
public interface IMediaBudget
|
|
62
|
+
{
|
|
63
|
+
/// <summary>
|
|
64
|
+
/// Reserva o custo estimado. <c>false</c> = estourou o teto, e o enqueue recusa com
|
|
65
|
+
/// <see cref="MediaErrorCode.BudgetExceeded"/>.
|
|
66
|
+
/// </summary>
|
|
67
|
+
ValueTask<bool> TryReserveAsync(MediaRequest request, decimal estimatedCostUsd, CancellationToken cancellationToken);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/// <summary>
|
|
71
|
+
/// Executa UM job: chama o provider, guarda os bytes, move o estado.
|
|
72
|
+
/// </summary>
|
|
73
|
+
/// <remarks>
|
|
74
|
+
/// A interface e publica para que o <c>BackgroundService</c> do projeto (ou o job Hangfire)
|
|
75
|
+
/// possa dispara-la; a <b>implementacao</b> e <c>internal</c>, porque e ela que segura o
|
|
76
|
+
/// <c>IMediaProvider</c>. Um handler pode pedir "rode este job"; nao pode pedir "gere estes
|
|
77
|
+
/// bytes agora".
|
|
78
|
+
/// </remarks>
|
|
79
|
+
public interface IMediaJobRunner
|
|
80
|
+
{
|
|
81
|
+
/// <summary>Roda o job ate o proximo estado estavel e devolve como ele ficou.</summary>
|
|
82
|
+
Task<MediaResult<MediaJob>> RunAsync(MediaJobId id, CancellationToken cancellationToken = default);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/// <summary>Relogio, para que o carimbo de tempo seja testavel sem esperar o mundo girar.</summary>
|
|
86
|
+
public interface IMediaClock
|
|
87
|
+
{
|
|
88
|
+
/// <summary>Agora.</summary>
|
|
89
|
+
DateTimeOffset UtcNow { get; }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/// <summary>O relogio do sistema.</summary>
|
|
93
|
+
public sealed class SystemMediaClock : IMediaClock
|
|
94
|
+
{
|
|
95
|
+
/// <inheritdoc />
|
|
96
|
+
public DateTimeOffset UtcNow => DateTimeOffset.UtcNow;
|
|
97
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
using System.Security.Cryptography;
|
|
2
|
+
|
|
3
|
+
namespace Morph.AiKit.Media;
|
|
4
|
+
|
|
5
|
+
/// <summary>
|
|
6
|
+
/// O endereco de um conteudo: sha256 dos BYTES.
|
|
7
|
+
/// </summary>
|
|
8
|
+
/// <remarks>
|
|
9
|
+
/// Responde "ja guardamos isto?" — nunca "ja pagamos por isto?", que e a pergunta do
|
|
10
|
+
/// <see cref="MediaIdempotencyKey"/>. Confundir as duas e o defeito caro: dois pedidos
|
|
11
|
+
/// diferentes podem produzir bytes identicos (e devem compartilhar UM arquivo), e o mesmo
|
|
12
|
+
/// pedido nunca deve ser pago duas vezes (mesmo que os bytes saiam diferentes).
|
|
13
|
+
/// </remarks>
|
|
14
|
+
/// <param name="Value">sha256 em hex minusculo.</param>
|
|
15
|
+
public readonly record struct MediaHash(string Value)
|
|
16
|
+
{
|
|
17
|
+
/// <summary>O hash do conteudo.</summary>
|
|
18
|
+
public static MediaHash Of(ReadOnlySpan<byte> bytes)
|
|
19
|
+
=> new(Convert.ToHexStringLower(SHA256.HashData(bytes)));
|
|
20
|
+
|
|
21
|
+
/// <summary>O hash, para log e para o caminho no blob.</summary>
|
|
22
|
+
public override string ToString() => Value;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/// <summary>
|
|
26
|
+
/// Onde os bytes ficam guardados. <b>A costura entre o kit e o blob do projeto</b> — o
|
|
27
|
+
/// unico ponto do <see cref="MediaStore"/> que um projeto precisa implementar.
|
|
28
|
+
/// </summary>
|
|
29
|
+
/// <remarks>
|
|
30
|
+
/// Deliberadamente sem tipo de infraestrutura na assinatura: nenhum <c>BlobClient</c>,
|
|
31
|
+
/// nenhum <c>S3</c>, nenhum caminho absoluto. A implementacao de producao vive no projeto;
|
|
32
|
+
/// a de teste vive nos fakes da suite. O kit nao conhece storage, pela mesma razao pela
|
|
33
|
+
/// qual <c>IConversationStore</c> nao conhece banco.
|
|
34
|
+
/// </remarks>
|
|
35
|
+
public interface IMediaBlobs
|
|
36
|
+
{
|
|
37
|
+
/// <summary>Se o caminho relativo ja existe. Nunca lanca por ausencia.</summary>
|
|
38
|
+
ValueTask<bool> ExistsAsync(string relativePath, CancellationToken cancellationToken);
|
|
39
|
+
|
|
40
|
+
/// <summary>Grava o conteudo no caminho relativo.</summary>
|
|
41
|
+
ValueTask WriteAsync(string relativePath, ReadOnlyMemory<byte> bytes, CancellationToken cancellationToken);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// <summary>O que o storage devolve sobre um conteudo guardado.</summary>
|
|
45
|
+
/// <param name="Hash">sha256 dos bytes.</param>
|
|
46
|
+
/// <param name="RelativePath">
|
|
47
|
+
/// O caminho RELATIVO, que e o que o banco guarda. Caminho absoluto ou URL de provider
|
|
48
|
+
/// amarram a linha ao disco de hoje ou a uma URL que expira — o Veo apaga o arquivo em 2
|
|
49
|
+
/// dias, e todo agregador devolve URL temporaria.
|
|
50
|
+
/// </param>
|
|
51
|
+
/// <param name="MediaType">MIME.</param>
|
|
52
|
+
/// <param name="AlreadyExisted">
|
|
53
|
+
/// Se o conteudo ja estava la. <b>Nao e enfeite:</b> e como o chamador sabe que a gravacao
|
|
54
|
+
/// foi deduplicada em vez de repetida.
|
|
55
|
+
/// </param>
|
|
56
|
+
public sealed record MediaStoreEntry(MediaHash Hash, string RelativePath, string MediaType, bool AlreadyExisted);
|
|
57
|
+
|
|
58
|
+
/// <summary>Storage de midia enderecado por conteudo.</summary>
|
|
59
|
+
public interface IMediaStore
|
|
60
|
+
{
|
|
61
|
+
/// <summary>Guarda os bytes e devolve o endereco. Conteudo repetido NAO e regravado.</summary>
|
|
62
|
+
ValueTask<MediaStoreEntry> PutAsync(
|
|
63
|
+
ReadOnlyMemory<byte> bytes,
|
|
64
|
+
string mediaType,
|
|
65
|
+
CancellationToken cancellationToken);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/// <summary>
|
|
69
|
+
/// Storage enderecado por conteudo: o caminho e derivado do sha256, e gravar o mesmo
|
|
70
|
+
/// conteudo duas vezes grava uma.
|
|
71
|
+
/// </summary>
|
|
72
|
+
/// <remarks>
|
|
73
|
+
/// <para>
|
|
74
|
+
/// O caminho e <c>ab/cd/<hash>.<ext></c>. Os dois niveis de prefixo existem
|
|
75
|
+
/// porque um diretorio unico com centenas de milhares de arquivos degrada listagem em
|
|
76
|
+
/// praticamente todo sistema de arquivos e em varios object stores.
|
|
77
|
+
/// </para>
|
|
78
|
+
/// <para>
|
|
79
|
+
/// A extensao vem do MIME e e o unico lugar do subsistema que faz esse mapa. Um MIME
|
|
80
|
+
/// desconhecido vira <c>.bin</c> em vez de recusa: perder a extensao e cosmetico, perder os
|
|
81
|
+
/// bytes pelos quais se pagou nao e.
|
|
82
|
+
/// </para>
|
|
83
|
+
/// </remarks>
|
|
84
|
+
public sealed class MediaStore : IMediaStore
|
|
85
|
+
{
|
|
86
|
+
private readonly IMediaBlobs _blobs;
|
|
87
|
+
|
|
88
|
+
/// <summary>Cria o storage sobre o blob do projeto.</summary>
|
|
89
|
+
/// <exception cref="ArgumentNullException">Blob nulo.</exception>
|
|
90
|
+
public MediaStore(IMediaBlobs blobs)
|
|
91
|
+
{
|
|
92
|
+
ArgumentNullException.ThrowIfNull(blobs);
|
|
93
|
+
_blobs = blobs;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/// <inheritdoc />
|
|
97
|
+
public async ValueTask<MediaStoreEntry> PutAsync(
|
|
98
|
+
ReadOnlyMemory<byte> bytes,
|
|
99
|
+
string mediaType,
|
|
100
|
+
CancellationToken cancellationToken)
|
|
101
|
+
{
|
|
102
|
+
ArgumentException.ThrowIfNullOrWhiteSpace(mediaType);
|
|
103
|
+
|
|
104
|
+
var hash = MediaHash.Of(bytes.Span);
|
|
105
|
+
var path = RelativePathFor(hash, mediaType);
|
|
106
|
+
|
|
107
|
+
if (await _blobs.ExistsAsync(path, cancellationToken).ConfigureAwait(false))
|
|
108
|
+
{
|
|
109
|
+
return new MediaStoreEntry(hash, path, mediaType, AlreadyExisted: true);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
await _blobs.WriteAsync(path, bytes, cancellationToken).ConfigureAwait(false);
|
|
113
|
+
return new MediaStoreEntry(hash, path, mediaType, AlreadyExisted: false);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/// <summary>O caminho relativo de um conteudo. Puro, para poder ser conferido em teste.</summary>
|
|
117
|
+
public static string RelativePathFor(MediaHash hash, string mediaType)
|
|
118
|
+
{
|
|
119
|
+
var value = hash.Value;
|
|
120
|
+
return $"{value[..2]}/{value[2..4]}/{value}{ExtensionFor(mediaType)}";
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/// <summary>MIME para extensao de arquivo. Desconhecido vira <c>.bin</c>, nunca recusa.</summary>
|
|
124
|
+
public static string ExtensionFor(string mediaType) => mediaType.ToLowerInvariant() switch
|
|
125
|
+
{
|
|
126
|
+
"image/png" => ".png",
|
|
127
|
+
"image/jpeg" or "image/jpg" => ".jpg",
|
|
128
|
+
"image/webp" => ".webp",
|
|
129
|
+
"video/mp4" => ".mp4",
|
|
130
|
+
"video/webm" => ".webm",
|
|
131
|
+
_ => ".bin",
|
|
132
|
+
};
|
|
133
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
namespace Morph.AiKit.Media;
|
|
2
|
+
|
|
3
|
+
/// <summary>
|
|
4
|
+
/// As pecas que o projeto precisa fornecer para o subsistema de midia funcionar.
|
|
5
|
+
/// </summary>
|
|
6
|
+
/// <remarks>
|
|
7
|
+
/// Nenhuma delas produz bytes. Repare no que NAO ha aqui: nao ha como o projeto injetar,
|
|
8
|
+
/// substituir ou alcancar um <c>IMediaProvider</c> — os adaptadores sao montados dentro do
|
|
9
|
+
/// assembly, por <see cref="MorphMedia"/>.
|
|
10
|
+
/// </remarks>
|
|
11
|
+
public sealed record MorphMediaOptions
|
|
12
|
+
{
|
|
13
|
+
/// <summary>Resolve alias para provider/modelo/tarifa. Obrigatorio.</summary>
|
|
14
|
+
public required IMediaAliasResolver AliasResolver { get; init; }
|
|
15
|
+
|
|
16
|
+
/// <summary>Onde os jobs vivem. Obrigatorio.</summary>
|
|
17
|
+
public required IMediaJobRepository Jobs { get; init; }
|
|
18
|
+
|
|
19
|
+
/// <summary>Onde os bytes vivem. Obrigatorio.</summary>
|
|
20
|
+
public required IMediaStore Store { get; init; }
|
|
21
|
+
|
|
22
|
+
/// <summary>
|
|
23
|
+
/// Constroi os clientes de SDK. Obrigatorio — e a costura com o provider de verdade.
|
|
24
|
+
/// </summary>
|
|
25
|
+
public required IMediaClientFactory Clients { get; init; }
|
|
26
|
+
|
|
27
|
+
/// <summary>O teto de custo. Nulo = sem teto (aceitavel so em ambiente de desenvolvimento).</summary>
|
|
28
|
+
public IMediaBudget? Budget { get; init; }
|
|
29
|
+
|
|
30
|
+
/// <summary>O relogio. Nulo = relogio do sistema.</summary>
|
|
31
|
+
public IMediaClock? Clock { get; init; }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/// <summary>
|
|
35
|
+
/// A raiz de composicao do subsistema de midia.
|
|
36
|
+
/// </summary>
|
|
37
|
+
/// <remarks>
|
|
38
|
+
/// <para>
|
|
39
|
+
/// <b>Por que uma fabrica estatica e nao um <c>AddMorphMedia(IServiceCollection)</c>:</b>
|
|
40
|
+
/// uma extensao de DI exigiria uma <c>PackageReference</c> explicita a
|
|
41
|
+
/// <c>Microsoft.Extensions.DependencyInjection.Abstractions</c>, e neste repositorio as
|
|
42
|
+
/// versoes de pacote sao GERADAS de <c>framework/ai-pin.json</c>. Acrescentar um pacote e
|
|
43
|
+
/// mexer no pin — uma decisao que se toma de proposito, com re-verificacao, e nao de
|
|
44
|
+
/// passagem numa feature de midia. Depender do pacote de forma TRANSITIVA seria pior: uma
|
|
45
|
+
/// dependencia escondida, que some no dia em que a arvore de dependencias mudar.
|
|
46
|
+
/// </para>
|
|
47
|
+
/// <para>
|
|
48
|
+
/// No projeto consumidor, o registro e uma linha, e o kit continua sem conhecer DI:
|
|
49
|
+
/// </para>
|
|
50
|
+
/// <code>
|
|
51
|
+
/// var media = MorphMedia.Create(options);
|
|
52
|
+
/// builder.Services.AddSingleton<IMediaGenerator>(media.Generator);
|
|
53
|
+
/// builder.Services.AddSingleton<IMediaJobRunner>(media.Runner);
|
|
54
|
+
/// </code>
|
|
55
|
+
/// </remarks>
|
|
56
|
+
public static class MorphMedia
|
|
57
|
+
{
|
|
58
|
+
/// <summary>
|
|
59
|
+
/// Monta o subsistema: o gerador publico e o executor de job, ambos sobre os mesmos
|
|
60
|
+
/// adaptadores internos.
|
|
61
|
+
/// </summary>
|
|
62
|
+
/// <exception cref="ArgumentNullException">Opcoes nulas.</exception>
|
|
63
|
+
public static MorphMediaComponents Create(MorphMediaOptions options)
|
|
64
|
+
{
|
|
65
|
+
ArgumentNullException.ThrowIfNull(options);
|
|
66
|
+
ArgumentNullException.ThrowIfNull(options.AliasResolver);
|
|
67
|
+
ArgumentNullException.ThrowIfNull(options.Jobs);
|
|
68
|
+
ArgumentNullException.ThrowIfNull(options.Store);
|
|
69
|
+
ArgumentNullException.ThrowIfNull(options.Clients);
|
|
70
|
+
|
|
71
|
+
var clock = options.Clock ?? new SystemMediaClock();
|
|
72
|
+
|
|
73
|
+
var generator = new MediaGenerator(
|
|
74
|
+
options.AliasResolver,
|
|
75
|
+
options.Jobs,
|
|
76
|
+
options.Budget,
|
|
77
|
+
clock);
|
|
78
|
+
|
|
79
|
+
var runner = new MediaWorker(
|
|
80
|
+
options.AliasResolver,
|
|
81
|
+
options.Jobs,
|
|
82
|
+
options.Store,
|
|
83
|
+
MediaProviderCatalog.Build(options.Clients),
|
|
84
|
+
clock);
|
|
85
|
+
|
|
86
|
+
return new MorphMediaComponents(generator, runner);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/// <summary>O que a raiz de composicao devolve. Duas interfaces, nenhuma delas com bytes.</summary>
|
|
91
|
+
/// <param name="Generator">O ponto de entrada do pedido.</param>
|
|
92
|
+
/// <param name="Runner">O executor de job, para o <c>BackgroundService</c> do projeto.</param>
|
|
93
|
+
public sealed record MorphMediaComponents(IMediaGenerator Generator, IMediaJobRunner Runner);
|
package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/GoogleImageProvider.cs
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
using Google.GenAI.Types;
|
|
2
|
+
|
|
3
|
+
namespace Morph.AiKit.Media.Providers;
|
|
4
|
+
|
|
5
|
+
/// <summary>
|
|
6
|
+
/// Adaptador de imagem do Google (familia Nano Banana). <b><c>internal</c></b> — ver
|
|
7
|
+
/// <see cref="IMediaProvider"/>.
|
|
8
|
+
/// </summary>
|
|
9
|
+
/// <remarks>
|
|
10
|
+
/// <para>
|
|
11
|
+
/// <b>Nao ha adaptador MEAI oficial para o Google</b> (medido em 2026-09-08: o unico
|
|
12
|
+
/// <c>AsIImageGenerator()</c> publicado e o de OpenAI/Azure OpenAI). O caminho e
|
|
13
|
+
/// <c>Google.GenAI</c> direto — <c>Models.GenerateContentAsync</c> com
|
|
14
|
+
/// <c>ResponseModalities</c> incluindo <c>"IMAGE"</c>, lendo os bytes de
|
|
15
|
+
/// <c>Candidates[0].Content.Parts[..].InlineData</c>.
|
|
16
|
+
/// </para>
|
|
17
|
+
/// <para>
|
|
18
|
+
/// <c>GenerateImagesAsync</c> do SDK <b>nao serve</b>: ela e a API do Imagen, cuja familia
|
|
19
|
+
/// <c>imagen-4.0-*</c> esta na tabela de deprecacoes de
|
|
20
|
+
/// <c>ai-agents/modalities-image-gen.md</c>.
|
|
21
|
+
/// </para>
|
|
22
|
+
/// </remarks>
|
|
23
|
+
internal sealed class GoogleImageProvider : IMediaProvider
|
|
24
|
+
{
|
|
25
|
+
private readonly IMediaClientFactory _clients;
|
|
26
|
+
|
|
27
|
+
public GoogleImageProvider(IMediaClientFactory clients)
|
|
28
|
+
{
|
|
29
|
+
ArgumentNullException.ThrowIfNull(clients);
|
|
30
|
+
_clients = clients;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/// <inheritdoc />
|
|
34
|
+
public string Provider => "google";
|
|
35
|
+
|
|
36
|
+
/// <inheritdoc />
|
|
37
|
+
public bool Supports(MediaKind kind) => kind == MediaKind.Image;
|
|
38
|
+
|
|
39
|
+
/// <inheritdoc />
|
|
40
|
+
public async Task<MediaResult<MediaArtifact>> ProduceAsync(
|
|
41
|
+
MediaRequest request,
|
|
42
|
+
MediaAliasBinding binding,
|
|
43
|
+
CancellationToken cancellationToken)
|
|
44
|
+
{
|
|
45
|
+
ArgumentNullException.ThrowIfNull(request);
|
|
46
|
+
ArgumentNullException.ThrowIfNull(binding);
|
|
47
|
+
|
|
48
|
+
var client = _clients.CreateGoogleClient(binding);
|
|
49
|
+
if (client is null)
|
|
50
|
+
{
|
|
51
|
+
return MediaResult<MediaArtifact>.Fail(
|
|
52
|
+
MediaErrorCode.ProviderFailure,
|
|
53
|
+
$"alias '{binding.Alias}': a fabrica de clientes nao construiu um Google.GenAI.Client.");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
var parts = new List<Part> { new() { Text = request.Prompt } };
|
|
57
|
+
|
|
58
|
+
// Cada referencia entra como InlineData, na ORDEM em que o prompt as indexa
|
|
59
|
+
// ("image 1 = o sofa"). Referencia nao indexada e referencia cujo uso o modelo
|
|
60
|
+
// escolhe sozinho.
|
|
61
|
+
foreach (var reference in request.References)
|
|
62
|
+
{
|
|
63
|
+
parts.Add(new Part
|
|
64
|
+
{
|
|
65
|
+
InlineData = new Blob
|
|
66
|
+
{
|
|
67
|
+
Data = reference.Bytes.ToArray(),
|
|
68
|
+
MimeType = reference.MediaType,
|
|
69
|
+
DisplayName = reference.Name,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
var config = new GenerateContentConfig
|
|
75
|
+
{
|
|
76
|
+
ResponseModalities = ["IMAGE", "TEXT"],
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
var response = await client.Models
|
|
80
|
+
.GenerateContentAsync(
|
|
81
|
+
binding.Model,
|
|
82
|
+
new Content { Role = "user", Parts = parts },
|
|
83
|
+
config,
|
|
84
|
+
cancellationToken)
|
|
85
|
+
.ConfigureAwait(false);
|
|
86
|
+
|
|
87
|
+
var blob = response.Candidates?
|
|
88
|
+
.SelectMany(c => c.Content?.Parts ?? [])
|
|
89
|
+
.Select(p => p.InlineData)
|
|
90
|
+
.FirstOrDefault(d => d?.Data is { Length: > 0 });
|
|
91
|
+
|
|
92
|
+
if (blob is null)
|
|
93
|
+
{
|
|
94
|
+
// Sem bytes e sem excecao: o caso tipico e filtro de conteudo. Terminal, e nao
|
|
95
|
+
// um erro tecnico que um retry resolveria.
|
|
96
|
+
return MediaResult<MediaArtifact>.Fail(
|
|
97
|
+
MediaErrorCode.PolicyBlocked,
|
|
98
|
+
$"alias '{binding.Alias}': a resposta nao trouxe imagem. O caso tipico e filtro de " +
|
|
99
|
+
"conteudo — e um bloqueio nao vira retry, porque retentar recebe o mesmo 'nao'.");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return MediaResult<MediaArtifact>.Ok(new MediaArtifact(
|
|
103
|
+
MediaKind.Image,
|
|
104
|
+
blob.MimeType ?? "image/png",
|
|
105
|
+
blob.Data,
|
|
106
|
+
RevisedPrompt: null,
|
|
107
|
+
ResponseId: response.ResponseId,
|
|
108
|
+
// SynthID vem embutido em toda imagem Gemini, e os bytes vao para o blob como
|
|
109
|
+
// chegaram: nenhum re-encode entre a resposta e o storage.
|
|
110
|
+
C2paPreserved: true));
|
|
111
|
+
}
|
|
112
|
+
}
|