@bluefly/openstandardagents 0.4.0 → 0.4.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/CHANGELOG.md +117 -0
- package/DEMO.md +212 -0
- package/README.md +75 -15
- package/dist/adapters/drupal/generator.d.ts +149 -0
- package/dist/adapters/drupal/generator.d.ts.map +1 -0
- package/dist/adapters/drupal/generator.js +1760 -0
- package/dist/adapters/drupal/generator.js.map +1 -0
- package/dist/adapters/drupal/index.d.ts +2 -0
- package/dist/adapters/drupal/index.d.ts.map +1 -1
- package/dist/adapters/drupal/index.js +3 -0
- package/dist/adapters/drupal/index.js.map +1 -1
- package/dist/adapters/npm/adapter.js +2 -2
- package/dist/adapters/npm/converter.js +3 -3
- package/dist/cli/banner.d.ts +21 -0
- package/dist/cli/banner.d.ts.map +1 -0
- package/dist/cli/banner.js +128 -0
- package/dist/cli/banner.js.map +1 -0
- package/dist/cli/commands/dev.command.d.ts +20 -0
- package/dist/cli/commands/dev.command.d.ts.map +1 -0
- package/dist/cli/commands/dev.command.js +78 -0
- package/dist/cli/commands/dev.command.js.map +1 -0
- package/dist/cli/commands/estimate.command.d.ts +12 -0
- package/dist/cli/commands/estimate.command.d.ts.map +1 -0
- package/dist/cli/commands/estimate.command.js +226 -0
- package/dist/cli/commands/estimate.command.js.map +1 -0
- package/dist/cli/commands/export-enhanced.command.d.ts +7 -0
- package/dist/cli/commands/export-enhanced.command.d.ts.map +1 -0
- package/dist/cli/commands/{export-v2.command.js → export-enhanced.command.js} +3 -3
- package/dist/cli/commands/export-enhanced.command.js.map +1 -0
- package/dist/cli/commands/export.command.d.ts.map +1 -1
- package/dist/cli/commands/export.command.js +82 -4
- package/dist/cli/commands/export.command.js.map +1 -1
- package/dist/cli/commands/init.command.d.ts.map +1 -1
- package/dist/cli/commands/init.command.js +2 -0
- package/dist/cli/commands/init.command.js.map +1 -1
- package/dist/cli/commands/test.command.d.ts +1 -0
- package/dist/cli/commands/test.command.d.ts.map +1 -1
- package/dist/cli/commands/test.command.js +172 -105
- package/dist/cli/commands/test.command.js.map +1 -1
- package/dist/cli/commands/types/wizard-config.types.d.ts +59 -0
- package/dist/cli/commands/types/wizard-config.types.d.ts.map +1 -0
- package/dist/cli/commands/types/wizard-config.types.js +34 -0
- package/dist/cli/commands/types/wizard-config.types.js.map +1 -0
- package/dist/cli/commands/upgrade.command.d.ts +9 -0
- package/dist/cli/commands/upgrade.command.d.ts.map +1 -0
- package/dist/cli/commands/upgrade.command.js +167 -0
- package/dist/cli/commands/upgrade.command.js.map +1 -0
- package/dist/cli/commands/wizard-api-first.command.d.ts +18 -0
- package/dist/cli/commands/wizard-api-first.command.d.ts.map +1 -0
- package/dist/cli/commands/wizard-api-first.command.js +854 -0
- package/dist/cli/commands/wizard-api-first.command.js.map +1 -0
- package/dist/cli/commands/wizard-interactive.command.d.ts +25 -0
- package/dist/cli/commands/wizard-interactive.command.d.ts.map +1 -0
- package/dist/cli/commands/wizard-interactive.command.js +1875 -0
- package/dist/cli/commands/wizard-interactive.command.js.map +1 -0
- package/dist/cli/commands/workspace.command.js +1 -1
- package/dist/cli/commands/workspace.command.js.map +1 -1
- package/dist/cli/index.js +9 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/schema-driven/index.d.ts +27 -0
- package/dist/cli/schema-driven/index.d.ts.map +1 -0
- package/dist/cli/schema-driven/index.js +34 -0
- package/dist/cli/schema-driven/index.js.map +1 -0
- package/dist/cli/schema-driven/schema-loader.d.ts +115 -0
- package/dist/cli/schema-driven/schema-loader.d.ts.map +1 -0
- package/dist/cli/schema-driven/schema-loader.js +270 -0
- package/dist/cli/schema-driven/schema-loader.js.map +1 -0
- package/dist/cli/schema-driven/ui-generator.d.ts +88 -0
- package/dist/cli/schema-driven/ui-generator.d.ts.map +1 -0
- package/dist/cli/schema-driven/ui-generator.js +326 -0
- package/dist/cli/schema-driven/ui-generator.js.map +1 -0
- package/dist/cli/wizard/interactive-wizard.d.ts +26 -0
- package/dist/cli/wizard/interactive-wizard.d.ts.map +1 -0
- package/dist/cli/wizard/interactive-wizard.js +296 -0
- package/dist/cli/wizard/interactive-wizard.js.map +1 -0
- package/dist/cli/wizard/template-catalog.d.ts +32 -0
- package/dist/cli/wizard/template-catalog.d.ts.map +1 -0
- package/dist/cli/wizard/template-catalog.js +99 -0
- package/dist/cli/wizard/template-catalog.js.map +1 -0
- package/dist/cli/wizard/use-cases.d.ts +37 -0
- package/dist/cli/wizard/use-cases.d.ts.map +1 -0
- package/dist/cli/wizard/use-cases.js +157 -0
- package/dist/cli/wizard/use-cases.js.map +1 -0
- package/dist/di-container.d.ts.map +1 -1
- package/dist/di-container.js +2 -0
- package/dist/di-container.js.map +1 -1
- package/dist/package.json +19 -9
- package/dist/runtime/agent-runner.d.ts +46 -0
- package/dist/runtime/agent-runner.d.ts.map +1 -0
- package/dist/runtime/agent-runner.js +346 -0
- package/dist/runtime/agent-runner.js.map +1 -0
- package/dist/sdks/kagent/crd-generator.d.ts +4 -0
- package/dist/sdks/kagent/crd-generator.d.ts.map +1 -1
- package/dist/sdks/kagent/crd-generator.js +83 -2
- package/dist/sdks/kagent/crd-generator.js.map +1 -1
- package/dist/sdks/kagent/k8s-resources-generator.d.ts +73 -0
- package/dist/sdks/kagent/k8s-resources-generator.d.ts.map +1 -0
- package/dist/sdks/kagent/k8s-resources-generator.js +286 -0
- package/dist/sdks/kagent/k8s-resources-generator.js.map +1 -0
- package/dist/sdks/kagent/types.d.ts +79 -0
- package/dist/sdks/kagent/types.d.ts.map +1 -1
- package/dist/sdks/shared/validation.d.ts +2 -2
- package/dist/services/cost-estimation/optimization-patterns.d.ts +23 -0
- package/dist/services/cost-estimation/optimization-patterns.d.ts.map +1 -0
- package/dist/services/cost-estimation/optimization-patterns.js +147 -0
- package/dist/services/cost-estimation/optimization-patterns.js.map +1 -0
- package/dist/services/cost-estimation/pricing.d.ts +29 -0
- package/dist/services/cost-estimation/pricing.d.ts.map +1 -0
- package/dist/services/cost-estimation/pricing.js +225 -0
- package/dist/services/cost-estimation/pricing.js.map +1 -0
- package/dist/services/cost-estimation/scenario-estimator.d.ts +59 -0
- package/dist/services/cost-estimation/scenario-estimator.d.ts.map +1 -0
- package/dist/services/cost-estimation/scenario-estimator.js +145 -0
- package/dist/services/cost-estimation/scenario-estimator.js.map +1 -0
- package/dist/services/cost-estimation/token-counter.service.d.ts +51 -0
- package/dist/services/cost-estimation/token-counter.service.d.ts.map +1 -0
- package/dist/services/cost-estimation/token-counter.service.js +125 -0
- package/dist/services/cost-estimation/token-counter.service.js.map +1 -0
- package/dist/services/dev-server/dev-server.service.d.ts +121 -0
- package/dist/services/dev-server/dev-server.service.d.ts.map +1 -0
- package/dist/services/dev-server/dev-server.service.js +290 -0
- package/dist/services/dev-server/dev-server.service.js.map +1 -0
- package/dist/services/dev-server/file-watcher.d.ts +101 -0
- package/dist/services/dev-server/file-watcher.d.ts.map +1 -0
- package/dist/services/dev-server/file-watcher.js +190 -0
- package/dist/services/dev-server/file-watcher.js.map +1 -0
- package/dist/services/dev-server/live-validator.d.ts +157 -0
- package/dist/services/dev-server/live-validator.d.ts.map +1 -0
- package/dist/services/dev-server/live-validator.js +301 -0
- package/dist/services/dev-server/live-validator.js.map +1 -0
- package/dist/services/dev-server/websocket-server.d.ts +137 -0
- package/dist/services/dev-server/websocket-server.d.ts.map +1 -0
- package/dist/services/dev-server/websocket-server.js +229 -0
- package/dist/services/dev-server/websocket-server.js.map +1 -0
- package/dist/services/export/anthropic/anthropic-exporter.d.ts +70 -0
- package/dist/services/export/anthropic/anthropic-exporter.d.ts.map +1 -0
- package/dist/services/export/anthropic/anthropic-exporter.js +576 -0
- package/dist/services/export/anthropic/anthropic-exporter.js.map +1 -0
- package/dist/services/export/anthropic/api-generator.d.ts +39 -0
- package/dist/services/export/anthropic/api-generator.d.ts.map +1 -0
- package/dist/services/export/anthropic/api-generator.js +395 -0
- package/dist/services/export/anthropic/api-generator.js.map +1 -0
- package/dist/services/export/anthropic/index.d.ts +18 -0
- package/dist/services/export/anthropic/index.d.ts.map +1 -0
- package/dist/services/export/anthropic/index.js +16 -0
- package/dist/services/export/anthropic/index.js.map +1 -0
- package/dist/services/export/anthropic/tools-generator.d.ts +35 -0
- package/dist/services/export/anthropic/tools-generator.d.ts.map +1 -0
- package/dist/services/export/anthropic/tools-generator.js +260 -0
- package/dist/services/export/anthropic/tools-generator.js.map +1 -0
- package/dist/services/export/langchain/api-generator.d.ts +17 -0
- package/dist/services/export/langchain/api-generator.d.ts.map +1 -0
- package/dist/services/export/langchain/api-generator.js +375 -0
- package/dist/services/export/langchain/api-generator.js.map +1 -0
- package/dist/services/export/langchain/callbacks-generator.d.ts +63 -0
- package/dist/services/export/langchain/callbacks-generator.d.ts.map +1 -0
- package/dist/services/export/langchain/callbacks-generator.js +408 -0
- package/dist/services/export/langchain/callbacks-generator.js.map +1 -0
- package/dist/services/export/langchain/error-handling-generator.d.ts +76 -0
- package/dist/services/export/langchain/error-handling-generator.d.ts.map +1 -0
- package/dist/services/export/langchain/error-handling-generator.js +522 -0
- package/dist/services/export/langchain/error-handling-generator.js.map +1 -0
- package/dist/services/export/langchain/index.d.ts +17 -0
- package/dist/services/export/langchain/index.d.ts.map +1 -0
- package/dist/services/export/langchain/index.js +13 -0
- package/dist/services/export/langchain/index.js.map +1 -0
- package/dist/services/export/langchain/langchain-exporter.d.ts +174 -0
- package/dist/services/export/langchain/langchain-exporter.d.ts.map +1 -0
- package/dist/services/export/langchain/langchain-exporter.js +953 -0
- package/dist/services/export/langchain/langchain-exporter.js.map +1 -0
- package/dist/services/export/langchain/langgraph-generator.d.ts +86 -0
- package/dist/services/export/langchain/langgraph-generator.d.ts.map +1 -0
- package/dist/services/export/langchain/langgraph-generator.js +473 -0
- package/dist/services/export/langchain/langgraph-generator.js.map +1 -0
- package/dist/services/export/langchain/langserve-generator.d.ts +95 -0
- package/dist/services/export/langchain/langserve-generator.d.ts.map +1 -0
- package/dist/services/export/langchain/langserve-generator.js +807 -0
- package/dist/services/export/langchain/langserve-generator.js.map +1 -0
- package/dist/services/export/langchain/memory-generator.d.ts +71 -0
- package/dist/services/export/langchain/memory-generator.d.ts.map +1 -0
- package/dist/services/export/langchain/memory-generator.js +1182 -0
- package/dist/services/export/langchain/memory-generator.js.map +1 -0
- package/dist/services/export/langchain/openapi-generator.d.ts +20 -0
- package/dist/services/export/langchain/openapi-generator.d.ts.map +1 -0
- package/dist/services/export/langchain/openapi-generator.js +364 -0
- package/dist/services/export/langchain/openapi-generator.js.map +1 -0
- package/dist/services/export/langchain/plan-execute-generator.d.ts +60 -0
- package/dist/services/export/langchain/plan-execute-generator.d.ts.map +1 -0
- package/dist/services/export/langchain/plan-execute-generator.js +679 -0
- package/dist/services/export/langchain/plan-execute-generator.js.map +1 -0
- package/dist/services/export/langchain/streaming-generator.d.ts +66 -0
- package/dist/services/export/langchain/streaming-generator.d.ts.map +1 -0
- package/dist/services/export/langchain/streaming-generator.js +749 -0
- package/dist/services/export/langchain/streaming-generator.js.map +1 -0
- package/dist/services/export/langchain/tools-generator.d.ts +67 -0
- package/dist/services/export/langchain/tools-generator.d.ts.map +1 -0
- package/dist/services/export/langchain/tools-generator.js +543 -0
- package/dist/services/export/langchain/tools-generator.js.map +1 -0
- package/dist/services/export/npm/express-generator.d.ts +23 -0
- package/dist/services/export/npm/express-generator.d.ts.map +1 -0
- package/dist/services/export/npm/express-generator.js +296 -0
- package/dist/services/export/npm/express-generator.js.map +1 -0
- package/dist/services/export/npm/index.d.ts +13 -0
- package/dist/services/export/npm/index.d.ts.map +1 -0
- package/dist/services/export/npm/index.js +11 -0
- package/dist/services/export/npm/index.js.map +1 -0
- package/dist/services/export/npm/npm-exporter.d.ts +142 -0
- package/dist/services/export/npm/npm-exporter.d.ts.map +1 -0
- package/dist/services/export/npm/npm-exporter.js +480 -0
- package/dist/services/export/npm/npm-exporter.js.map +1 -0
- package/dist/services/export/npm/openapi-generator.d.ts +19 -0
- package/dist/services/export/npm/openapi-generator.d.ts.map +1 -0
- package/dist/services/export/npm/openapi-generator.js +428 -0
- package/dist/services/export/npm/openapi-generator.js.map +1 -0
- package/dist/services/export/npm/package-json-generator.d.ts +31 -0
- package/dist/services/export/npm/package-json-generator.d.ts.map +1 -0
- package/dist/services/export/npm/package-json-generator.js +153 -0
- package/dist/services/export/npm/package-json-generator.js.map +1 -0
- package/dist/services/export/npm/typescript-generator.d.ts +69 -0
- package/dist/services/export/npm/typescript-generator.d.ts.map +1 -0
- package/dist/services/export/npm/typescript-generator.js +437 -0
- package/dist/services/export/npm/typescript-generator.js.map +1 -0
- package/dist/services/export/testing/index.d.ts +8 -0
- package/dist/services/export/testing/index.d.ts.map +1 -0
- package/dist/services/export/testing/index.js +7 -0
- package/dist/services/export/testing/index.js.map +1 -0
- package/dist/services/export/testing/test-generator.d.ts +178 -0
- package/dist/services/export/testing/test-generator.d.ts.map +1 -0
- package/dist/services/export/testing/test-generator.js +2542 -0
- package/dist/services/export/testing/test-generator.js.map +1 -0
- package/dist/services/test-runner/mock-llm.service.d.ts +77 -0
- package/dist/services/test-runner/mock-llm.service.d.ts.map +1 -0
- package/dist/services/test-runner/mock-llm.service.js +173 -0
- package/dist/services/test-runner/mock-llm.service.js.map +1 -0
- package/dist/services/test-runner/scenarios.d.ts +36 -0
- package/dist/services/test-runner/scenarios.d.ts.map +1 -0
- package/dist/services/test-runner/scenarios.js +196 -0
- package/dist/services/test-runner/scenarios.js.map +1 -0
- package/dist/services/test-runner/test-runner.service.d.ts +19 -1
- package/dist/services/test-runner/test-runner.service.d.ts.map +1 -1
- package/dist/services/test-runner/test-runner.service.js +72 -6
- package/dist/services/test-runner/test-runner.service.js.map +1 -1
- package/dist/services/validation/best-practices-validator.d.ts +84 -0
- package/dist/services/validation/best-practices-validator.d.ts.map +1 -0
- package/dist/services/validation/best-practices-validator.js +499 -0
- package/dist/services/validation/best-practices-validator.js.map +1 -0
- package/dist/services/validation/cost-estimator.d.ts +69 -0
- package/dist/services/validation/cost-estimator.d.ts.map +1 -0
- package/dist/services/validation/cost-estimator.js +221 -0
- package/dist/services/validation/cost-estimator.js.map +1 -0
- package/dist/services/validation/enhanced-validator.d.ts +78 -0
- package/dist/services/validation/enhanced-validator.d.ts.map +1 -0
- package/dist/services/validation/enhanced-validator.js +212 -0
- package/dist/services/validation/enhanced-validator.js.map +1 -0
- package/dist/services/validation/index.d.ts +13 -0
- package/dist/services/validation/index.d.ts.map +1 -0
- package/dist/services/validation/index.js +9 -0
- package/dist/services/validation/index.js.map +1 -0
- package/dist/services/validation/security-validator.d.ts +81 -0
- package/dist/services/validation/security-validator.d.ts.map +1 -0
- package/dist/services/validation/security-validator.js +328 -0
- package/dist/services/validation/security-validator.js.map +1 -0
- package/dist/services/wizard/prompts.d.ts +71 -0
- package/dist/services/wizard/prompts.d.ts.map +1 -0
- package/dist/services/wizard/prompts.js +322 -0
- package/dist/services/wizard/prompts.js.map +1 -0
- package/dist/services/wizard/wizard.service.d.ts +60 -0
- package/dist/services/wizard/wizard.service.d.ts.map +1 -0
- package/dist/services/wizard/wizard.service.js +261 -0
- package/dist/services/wizard/wizard.service.js.map +1 -0
- package/dist/types/personality.zod.d.ts +23 -23
- package/dist/utils/version.d.ts +1 -1
- package/dist/utils/version.js +1 -1
- package/dist/version-management/core/version-manager.test.js.map +1 -1
- package/dist/version.d.ts +62 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +73 -0
- package/dist/version.js.map +1 -0
- package/examples/a2a/agent-handoff.ossa.yaml +1 -1
- package/examples/a2a/service-discovery.ossa.yaml +1 -1
- package/examples/adapters/drupal-eca-mapping.yaml +1 -1
- package/examples/adapters/drupal-eca-task.yaml +1 -1
- package/examples/adapters/drupal-flowdrop-mapping.yaml +1 -1
- package/examples/adapters/drupal-maestro-mapping.yaml +1 -1
- package/examples/adapters/mistral-agent.yaml +1 -1
- package/examples/adapters/symfony-messenger-task.yaml +1 -1
- package/examples/adapters/symfony-messenger-workflow.yaml +1 -1
- package/examples/adk-integration/code-review-workflow.yml +1 -1
- package/examples/adk-integration/customer-support.yml +1 -1
- package/examples/adk-integration/data-pipeline.yml +1 -1
- package/examples/advanced/reasoning-agent.yaml +1 -1
- package/examples/advanced/workflows/hybrid-model-strategy.yaml +1 -1
- package/examples/agent-manifests/critics/critic-agent.yaml +1 -1
- package/examples/agent-manifests/governors/governor-agent.yaml +1 -1
- package/examples/agent-manifests/integrators/integrator-agent.yaml +1 -1
- package/examples/agent-manifests/judges/judge-agent.yaml +1 -1
- package/examples/agent-manifests/monitors/monitor-agent.yaml +1 -1
- package/examples/agent-manifests/orchestrators/orchestrator-agent.yaml +1 -1
- package/examples/agent-manifests/sample-compliant-agent.yaml +1 -1
- package/examples/agent-manifests/workers/worker-agent.yaml +1 -1
- package/examples/agents/01-customer-support-bot/.env.example +32 -0
- package/examples/agents/01-customer-support-bot/Dockerfile +30 -0
- package/examples/agents/01-customer-support-bot/README.md +295 -0
- package/examples/agents/01-customer-support-bot/agent.ossa.yaml +172 -0
- package/examples/agents/01-customer-support-bot/docker-compose.yml +55 -0
- package/examples/agents/01-customer-support-bot/openapi.yaml +238 -0
- package/examples/agents/01-customer-support-bot/package.json +48 -0
- package/examples/agents/02-code-review-agent/README.md +72 -0
- package/examples/agents/02-code-review-agent/agent.ossa.yaml +239 -0
- package/examples/agents/02-code-review-agent/docker-compose.yml +22 -0
- package/examples/agents/02-code-review-agent/openapi.yaml +150 -0
- package/examples/agents/03-data-analysis-agent/README.md +51 -0
- package/examples/agents/03-data-analysis-agent/agent.ossa.yaml +97 -0
- package/examples/agents/03-data-analysis-agent/openapi.yaml +74 -0
- package/examples/agents/04-content-moderator/README.md +55 -0
- package/examples/agents/04-content-moderator/agent.ossa.yaml +131 -0
- package/examples/agents/04-content-moderator/openapi.yaml +50 -0
- package/examples/agents/05-sales-assistant/README.md +37 -0
- package/examples/agents/05-sales-assistant/agent.ossa.yaml +146 -0
- package/examples/agents/05-sales-assistant/openapi.yaml +59 -0
- package/examples/agents/06-devops-agent/README.md +39 -0
- package/examples/agents/06-devops-agent/agent.ossa.yaml +141 -0
- package/examples/agents/06-devops-agent/openapi.yaml +51 -0
- package/examples/agents/07-research-assistant/README.md +31 -0
- package/examples/agents/07-research-assistant/agent.ossa.yaml +119 -0
- package/examples/agents/07-research-assistant/openapi.yaml +56 -0
- package/examples/agents/08-email-triage-agent/README.md +33 -0
- package/examples/agents/08-email-triage-agent/agent.ossa.yaml +133 -0
- package/examples/agents/08-email-triage-agent/openapi.yaml +41 -0
- package/examples/agents/09-security-scanner/README.md +49 -0
- package/examples/agents/09-security-scanner/agent.ossa.yaml +174 -0
- package/examples/agents/09-security-scanner/openapi.yaml +46 -0
- package/examples/agents/10-meeting-assistant/README.md +53 -0
- package/examples/agents/10-meeting-assistant/agent.ossa.yaml +211 -0
- package/examples/agents/10-meeting-assistant/docker-compose.yml +27 -0
- package/examples/agents/10-meeting-assistant/openapi.yaml +131 -0
- package/examples/agents/COMPLETION_REPORT.txt +272 -0
- package/examples/agents/INDEX.md +296 -0
- package/examples/agents/README.md +452 -0
- package/examples/agents/SUMMARY.md +362 -0
- package/examples/agents/TEST_RESULTS.md +458 -0
- package/examples/agents/architecture-healer-enterprise.yaml +1 -1
- package/examples/agents/dependency-healer-npm.yaml +1 -1
- package/examples/agents/spec-healer-openapi.yaml +1 -1
- package/examples/agents/wiki-healer-production.yaml +1 -1
- package/examples/agents-md/code-agent.ossa.json +1 -1
- package/examples/agents-md/monorepo-agent.ossa.yaml +1 -1
- package/examples/anthropic/claude-assistant.ossa.json +1 -1
- package/examples/autogen/multi-agent.ossa.json +1 -1
- package/examples/autonomous-evolution/self-evolving-agent.ossa.yaml +1 -1
- package/examples/build-once-use-everywhere/agent.ossa.yaml +1 -1
- package/examples/claude-code/code-reviewer.ossa.yaml +1 -1
- package/examples/claude-code/ossa-validator.ossa.yaml +1 -1
- package/examples/common_npm/agent-router.ossa.yaml +2 -2
- package/examples/contracts/data-consumer.ossa.yaml +1 -1
- package/examples/contracts/data-producer-v2.ossa.yaml +1 -1
- package/examples/contracts/data-producer.ossa.yaml +1 -1
- package/examples/crewai/research-team.ossa.json +1 -1
- package/examples/cursor/code-review-agent.ossa.json +1 -1
- package/examples/drupal/QUICKSTART.md +439 -0
- package/examples/drupal/ai_agents_ossa-module/.agents/example-agent/agent.ossa.yaml +1 -1
- package/examples/drupal/content-moderator.ossa.yaml +107 -0
- package/examples/drupal/gitlab-ml-recommender.ossa.yaml +2 -2
- package/examples/economics/marketplace-agent.ossa.json +1 -1
- package/examples/export/langchain/production-agent-with-memory/README.md +373 -0
- package/examples/export/langchain/production-agent-with-memory/agent.ossa.yaml +97 -0
- package/examples/export/langchain/production-agent-with-streaming/README.md +617 -0
- package/examples/export/langchain/production-agent-with-streaming/agent.ossa.yaml +100 -0
- package/examples/export/langchain/production-agent-with-streaming/client-example.py +263 -0
- package/examples/export/langchain/production-agent-with-tools/README.md +296 -0
- package/examples/export/langchain/production-agent-with-tools/agent.ossa.yaml +216 -0
- package/examples/export/langchain-export-example.ts +246 -0
- package/examples/export/langserve-export-example.ts +246 -0
- package/examples/export/test-generation-example.ts +457 -0
- package/examples/extensions/agents-md-advanced.yml +1 -1
- package/examples/extensions/agents-md-basic.yml +1 -1
- package/examples/extensions/agents-md-sync.yml +1 -1
- package/examples/extensions/agents-md-v1.yml +1 -1
- package/examples/extensions/drupal-v1.yml +1 -1
- package/examples/extensions/encryption-multi-provider.yaml +4 -4
- package/examples/extensions/kagent-v1.yml +1 -1
- package/examples/extensions/knowledge-sources.yaml +1 -1
- package/examples/extensions/mcp-full-featured.yaml +1 -1
- package/examples/genetics/breeding-agent.ossa.json +1 -1
- package/examples/getting-started/01-minimal-agent.ossa.yaml +1 -1
- package/examples/getting-started/02-agent-with-tools.ossa.yaml +1 -1
- package/examples/getting-started/03-agent-with-safety.ossa.yaml +1 -1
- package/examples/getting-started/04-agent-with-messaging.ossa.yaml +1 -1
- package/examples/getting-started/05-workflow-composition.ossa.yaml +1 -1
- package/examples/getting-started/hello-world-complete.ossa.yaml +1 -1
- package/examples/integration-patterns/agent-to-agent-orchestration.ossa.yaml +1 -1
- package/examples/kagent/compliance-validator.ossa.yaml +1 -1
- package/examples/kagent/cost-optimizer.ossa.yaml +1 -1
- package/examples/kagent/documentation-agent.ossa.yaml +1 -1
- package/examples/kagent/k8s-troubleshooter-v1.ossa.yaml +2 -2
- package/examples/kagent/k8s-troubleshooter.ossa.yaml +1 -1
- package/examples/kagent/security-scanner.ossa.yaml +1 -1
- package/examples/langchain/chain-agent.ossa.json +1 -1
- package/examples/langflow/workflow-agent.ossa.json +1 -1
- package/examples/langgraph/state-machine-agent.ossa.json +1 -1
- package/examples/lifecycle/mentoring-agent.ossa.json +1 -1
- package/examples/llamaindex/rag-agent.ossa.json +1 -1
- package/examples/mcp/database-mcp.ossa.yaml +1 -1
- package/examples/mcp/filesystem-mcp.ossa.yaml +1 -1
- package/examples/messaging/dependency-healer.ossa.yaml +1 -1
- package/examples/messaging/incident-responder.ossa.yaml +1 -1
- package/examples/messaging/routing-rules.ossa.yaml +1 -1
- package/examples/messaging/security-scanner.ossa.yaml +1 -1
- package/examples/migration-guides/from-langchain-to-ossa.yaml +4 -4
- package/examples/migrations/langchain/01-python-react-agent-after.ossa.yaml +1 -1
- package/examples/migrations/langchain/02-typescript-conversational-after.ossa.yaml +1 -1
- package/examples/migrations/langchain/03-sequential-chain-after.ossa.yaml +1 -1
- package/examples/migrations/langchain/04-config-based-after.ossa.yaml +1 -1
- package/examples/migrations/swarm-to-ossa/after-handoffs.ossa.yaml +6 -6
- package/examples/migrations/swarm-to-ossa/after-triage-agent.ossa.yaml +3 -3
- package/examples/multi-agent/conditional-router.ossa.yaml +1 -1
- package/examples/multi-agent/parallel-execution.ossa.yaml +1 -1
- package/examples/multi-agent/sequential-pipeline.ossa.yaml +1 -1
- package/examples/multi-agent-research-workflow.ossa.yaml +133 -0
- package/examples/multi-platform/single-manifest/agent.ossa.yaml +1 -1
- package/examples/npm-export-example.ts +150 -0
- package/examples/observability/activity-stream-full.yaml +1 -1
- package/examples/openai/basic-agent.ossa.yaml +1 -1
- package/examples/openai/multi-tool-agent.ossa.json +1 -1
- package/examples/openai/swarm-agent.ossa.json +1 -1
- package/examples/ossa-templates/01-code-assistant.ossa.yaml +1 -1
- package/examples/ossa-templates/02-security-scanner.ossa.yaml +1 -1
- package/examples/ossa-templates/03-ci-pipeline.ossa.yaml +1 -1
- package/examples/ossa-templates/04-code-reviewer.ossa.yaml +1 -1
- package/examples/ossa-templates/05-doc-generator.ossa.yaml +1 -1
- package/examples/ossa-templates/06-compliance-validator.ossa.yaml +1 -1
- package/examples/ossa-templates/07-workflow-orchestrator.ossa.yaml +1 -1
- package/examples/ossa-templates/08-content-writer.ossa.yaml +1 -1
- package/examples/ossa-templates/09-test-generator.ossa.yaml +1 -1
- package/examples/ossa-templates/10-data-transformer.ossa.yaml +1 -1
- package/examples/ossa-templates/11-react-performance-expert.ossa.yaml +1 -1
- package/examples/ossa-templates/12-typescript-type-safety-expert.ossa.yaml +1 -1
- package/examples/ossa-templates/13-accessibility-champion.ossa.yaml +1 -1
- package/examples/ossa-templates/14-security-hardening-agent.ossa.yaml +1 -1
- package/examples/production/document-analyzer-openai.yml +1 -1
- package/examples/production-ready/01-customer-support-bot/.env.example +32 -0
- package/examples/production-ready/01-customer-support-bot/Dockerfile +30 -0
- package/examples/production-ready/01-customer-support-bot/README.md +295 -0
- package/examples/production-ready/01-customer-support-bot/agent.ossa.yaml +172 -0
- package/examples/production-ready/01-customer-support-bot/docker-compose.yml +55 -0
- package/examples/production-ready/01-customer-support-bot/openapi.yaml +238 -0
- package/examples/production-ready/01-customer-support-bot/package.json +48 -0
- package/examples/production-ready/02-code-review-agent/README.md +72 -0
- package/examples/production-ready/02-code-review-agent/agent.ossa.yaml +239 -0
- package/examples/production-ready/02-code-review-agent/docker-compose.yml +22 -0
- package/examples/production-ready/02-code-review-agent/openapi.yaml +150 -0
- package/examples/production-ready/03-data-analysis-agent/README.md +51 -0
- package/examples/production-ready/03-data-analysis-agent/agent.ossa.yaml +97 -0
- package/examples/production-ready/03-data-analysis-agent/openapi.yaml +74 -0
- package/examples/production-ready/04-content-moderator/README.md +55 -0
- package/examples/production-ready/04-content-moderator/agent.ossa.yaml +131 -0
- package/examples/production-ready/04-content-moderator/openapi.yaml +50 -0
- package/examples/production-ready/05-sales-assistant/README.md +37 -0
- package/examples/production-ready/05-sales-assistant/agent.ossa.yaml +146 -0
- package/examples/production-ready/05-sales-assistant/openapi.yaml +59 -0
- package/examples/production-ready/06-devops-agent/README.md +39 -0
- package/examples/production-ready/06-devops-agent/agent.ossa.yaml +141 -0
- package/examples/production-ready/06-devops-agent/openapi.yaml +51 -0
- package/examples/production-ready/07-research-assistant/README.md +31 -0
- package/examples/production-ready/07-research-assistant/agent.ossa.yaml +119 -0
- package/examples/production-ready/07-research-assistant/openapi.yaml +56 -0
- package/examples/production-ready/08-email-triage-agent/README.md +33 -0
- package/examples/production-ready/08-email-triage-agent/agent.ossa.yaml +133 -0
- package/examples/production-ready/08-email-triage-agent/openapi.yaml +41 -0
- package/examples/production-ready/09-security-scanner/README.md +49 -0
- package/examples/production-ready/09-security-scanner/agent.ossa.yaml +174 -0
- package/examples/production-ready/09-security-scanner/openapi.yaml +46 -0
- package/examples/production-ready/10-meeting-assistant/README.md +53 -0
- package/examples/production-ready/10-meeting-assistant/agent.ossa.yaml +211 -0
- package/examples/production-ready/10-meeting-assistant/docker-compose.yml +27 -0
- package/examples/production-ready/10-meeting-assistant/openapi.yaml +131 -0
- package/examples/production-ready/COMPLETION_REPORT.txt +272 -0
- package/examples/production-ready/INDEX.md +296 -0
- package/examples/production-ready/README.md +452 -0
- package/examples/production-ready/SUMMARY.md +362 -0
- package/examples/production-ready/TEST_RESULTS.md +458 -0
- package/examples/quickstart/support-agent.ossa.yaml +1 -1
- package/examples/real-world/gitlab-cicd-optimizer.ossa.yaml +1 -1
- package/examples/real-world/rag-documentation-assistant.ossa.yaml +1 -1
- package/examples/registry/agents/code-reviewer/agent.yaml +1 -1
- package/examples/registry/agents/security-scanner/agent.yaml +1 -1
- package/examples/runtime-adapters/bedrock-claude-example.ossa.yaml +1 -1
- package/examples/schema/reusable-components.yaml +1 -1
- package/examples/showcase/ci-pipeline.ossa.yaml +1 -1
- package/examples/showcase/code-assistant.ossa.yaml +1 -1
- package/examples/showcase/code-reviewer.ossa.yaml +1 -1
- package/examples/showcase/compliance-validator.ossa.yaml +1 -1
- package/examples/showcase/content-writer.ossa.yaml +1 -1
- package/examples/showcase/data-transformer.ossa.yaml +1 -1
- package/examples/showcase/doc-generator.ossa.yaml +1 -1
- package/examples/showcase/security-scanner.ossa.yaml +1 -1
- package/examples/showcase/test-generator.ossa.yaml +1 -1
- package/examples/showcase/workflow-orchestrator.ossa.yaml +1 -1
- package/examples/skills-example.ossa.yaml +140 -0
- package/examples/swarm/pso-optimizer.ossa.json +1 -1
- package/examples/tasks/batch-email-sender.yaml +1 -1
- package/examples/tasks/data-transform.yaml +1 -1
- package/examples/tasks/publish-content.yaml +1 -1
- package/examples/templates/ossa-compliance.yaml +1 -1
- package/examples/unified/security-scanner.ossa.yaml +1 -1
- package/examples/v0.3.6-features/genetics-breeding-advanced.ossa.yaml +1 -1
- package/examples/v0.3.6-features/genetics-breeding-simple.ossa.yaml +1 -1
- package/examples/v0.3.6-features/genetics-fitness-scoring.ossa.yaml +1 -1
- package/examples/vercel/edge-agent.ossa.json +1 -1
- package/examples/workflows/batch-email-campaign.yaml +1 -1
- package/examples/workflows/content-review-publish.yaml +1 -1
- package/examples/workflows/simple-etl.yaml +1 -1
- package/openapi/cli/openapi.yaml +221 -5
- package/package.json +17 -7
- package/dist/cli/commands/export-v2.command.d.ts +0 -7
- package/dist/cli/commands/export-v2.command.d.ts.map +0 -1
- package/dist/cli/commands/export-v2.command.js.map +0 -1
|
@@ -0,0 +1,1760 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drupal Module Generator for OSSA Agents
|
|
3
|
+
*
|
|
4
|
+
* Generates complete, production-ready Drupal modules from OSSA agent manifests.
|
|
5
|
+
*
|
|
6
|
+
* Generated modules include:
|
|
7
|
+
* - MODULE.info.yml (module metadata)
|
|
8
|
+
* - MODULE.services.yml (DI configuration)
|
|
9
|
+
* - src/Service/AgentExecutor (wrapper around ossa/symfony-bundle)
|
|
10
|
+
* - src/Plugin/QueueWorker (async execution support)
|
|
11
|
+
* - src/Controller (admin UI and API endpoints)
|
|
12
|
+
* - src/Entity (agent result storage)
|
|
13
|
+
* - src/Form (configuration forms)
|
|
14
|
+
* - MODULE.module (Drupal hooks: entity_presave, cron, etc.)
|
|
15
|
+
* - templates/*.html.twig (Twig templates)
|
|
16
|
+
* - composer.json (with ossa/symfony-bundle dependency)
|
|
17
|
+
* - config/schema/MODULE.schema.yml (configuration schema)
|
|
18
|
+
* - config/install/*.yml (default configuration)
|
|
19
|
+
*
|
|
20
|
+
* SOLID Principles:
|
|
21
|
+
* - Single Responsibility: Drupal module generation only
|
|
22
|
+
* - Dependency Inversion: Uses ossa/symfony-bundle for agent execution
|
|
23
|
+
* - Interface Segregation: Separate interfaces for different module components
|
|
24
|
+
*
|
|
25
|
+
* DRY: Reuses Symfony bundle patterns, no duplication
|
|
26
|
+
*/
|
|
27
|
+
import { BaseAdapter } from '../base/adapter.interface.js';
|
|
28
|
+
export class DrupalModuleGenerator extends BaseAdapter {
|
|
29
|
+
platform = 'drupal';
|
|
30
|
+
displayName = 'Drupal Module (Full)';
|
|
31
|
+
description = 'Production-ready Drupal module with OSSA/Symfony integration';
|
|
32
|
+
supportedVersions = ['v{{VERSION}}'];
|
|
33
|
+
/**
|
|
34
|
+
* Generate complete Drupal module from OSSA manifest
|
|
35
|
+
*/
|
|
36
|
+
async export(manifest, options) {
|
|
37
|
+
const startTime = Date.now();
|
|
38
|
+
try {
|
|
39
|
+
// Validate manifest
|
|
40
|
+
if (options?.validate !== false) {
|
|
41
|
+
const validation = await this.validate(manifest);
|
|
42
|
+
if (!validation.valid) {
|
|
43
|
+
return this.createResult(false, [], `Validation failed: ${validation.errors?.map((e) => e.message).join(', ')}`, {
|
|
44
|
+
duration: Date.now() - startTime,
|
|
45
|
+
warnings: validation.warnings?.map((w) => w.message),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const moduleName = this.sanitizeModuleName(manifest.metadata?.name || 'ossa_agent');
|
|
50
|
+
const className = this.toClassName(moduleName);
|
|
51
|
+
// Default options
|
|
52
|
+
const opts = {
|
|
53
|
+
includeQueueWorker: true,
|
|
54
|
+
includeEntity: true,
|
|
55
|
+
includeController: true,
|
|
56
|
+
includeConfigForm: true,
|
|
57
|
+
includeHooks: true,
|
|
58
|
+
includeViews: true,
|
|
59
|
+
coreVersion: '^10 || ^11',
|
|
60
|
+
validate: options?.validate ?? true,
|
|
61
|
+
...options,
|
|
62
|
+
};
|
|
63
|
+
const files = [];
|
|
64
|
+
// ===================================================================
|
|
65
|
+
// Core Module Files
|
|
66
|
+
// ===================================================================
|
|
67
|
+
// MODULE.info.yml
|
|
68
|
+
files.push(this.createFile(`${moduleName}/${moduleName}.info.yml`, this.generateInfoYml(manifest, moduleName, opts), 'config'));
|
|
69
|
+
// MODULE.services.yml
|
|
70
|
+
files.push(this.createFile(`${moduleName}/${moduleName}.services.yml`, this.generateServicesYml(manifest, moduleName, className, opts), 'config'));
|
|
71
|
+
// composer.json
|
|
72
|
+
files.push(this.createFile(`${moduleName}/composer.json`, this.generateComposerJson(manifest, moduleName), 'config'));
|
|
73
|
+
// MODULE.module (hooks)
|
|
74
|
+
if (opts.includeHooks) {
|
|
75
|
+
files.push(this.createFile(`${moduleName}/${moduleName}.module`, this.generateModuleHooks(manifest, moduleName, className), 'code', 'php'));
|
|
76
|
+
}
|
|
77
|
+
// ===================================================================
|
|
78
|
+
// Service Classes
|
|
79
|
+
// ===================================================================
|
|
80
|
+
// src/Service/AgentExecutorService.php
|
|
81
|
+
files.push(this.createFile(`${moduleName}/src/Service/AgentExecutorService.php`, this.generateAgentExecutorService(manifest, moduleName, className), 'code', 'php'));
|
|
82
|
+
// ===================================================================
|
|
83
|
+
// Queue Worker (Async Execution)
|
|
84
|
+
// ===================================================================
|
|
85
|
+
if (opts.includeQueueWorker) {
|
|
86
|
+
files.push(this.createFile(`${moduleName}/src/Plugin/QueueWorker/AgentQueueWorker.php`, this.generateQueueWorker(manifest, moduleName, className), 'code', 'php'));
|
|
87
|
+
}
|
|
88
|
+
// ===================================================================
|
|
89
|
+
// Entity (Result Storage)
|
|
90
|
+
// ===================================================================
|
|
91
|
+
if (opts.includeEntity) {
|
|
92
|
+
// Entity class
|
|
93
|
+
files.push(this.createFile(`${moduleName}/src/Entity/AgentResult.php`, this.generateEntityClass(manifest, moduleName, className), 'code', 'php'));
|
|
94
|
+
// Entity interface
|
|
95
|
+
files.push(this.createFile(`${moduleName}/src/Entity/AgentResultInterface.php`, this.generateEntityInterface(moduleName), 'code', 'php'));
|
|
96
|
+
// Views data
|
|
97
|
+
if (opts.includeViews) {
|
|
98
|
+
files.push(this.createFile(`${moduleName}/${moduleName}.views.inc`, this.generateViewsData(moduleName, className), 'code', 'php'));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// ===================================================================
|
|
102
|
+
// Controller (Admin UI + API)
|
|
103
|
+
// ===================================================================
|
|
104
|
+
if (opts.includeController) {
|
|
105
|
+
files.push(this.createFile(`${moduleName}/src/Controller/AgentController.php`, this.generateController(manifest, moduleName, className), 'code', 'php'));
|
|
106
|
+
// Routing
|
|
107
|
+
files.push(this.createFile(`${moduleName}/${moduleName}.routing.yml`, this.generateRouting(moduleName), 'config'));
|
|
108
|
+
}
|
|
109
|
+
// ===================================================================
|
|
110
|
+
// Configuration Form
|
|
111
|
+
// ===================================================================
|
|
112
|
+
if (opts.includeConfigForm) {
|
|
113
|
+
files.push(this.createFile(`${moduleName}/src/Form/AgentConfigForm.php`, this.generateConfigForm(manifest, moduleName, className), 'code', 'php'));
|
|
114
|
+
// Menu links
|
|
115
|
+
files.push(this.createFile(`${moduleName}/${moduleName}.links.menu.yml`, this.generateMenuLinks(moduleName), 'config'));
|
|
116
|
+
}
|
|
117
|
+
// ===================================================================
|
|
118
|
+
// Configuration Schema
|
|
119
|
+
// ===================================================================
|
|
120
|
+
files.push(this.createFile(`${moduleName}/config/schema/${moduleName}.schema.yml`, this.generateConfigSchema(moduleName), 'config'));
|
|
121
|
+
// Default configuration
|
|
122
|
+
files.push(this.createFile(`${moduleName}/config/install/${moduleName}.settings.yml`, this.generateDefaultConfig(manifest), 'config'));
|
|
123
|
+
// ===================================================================
|
|
124
|
+
// Templates
|
|
125
|
+
// ===================================================================
|
|
126
|
+
files.push(this.createFile(`${moduleName}/templates/agent-result.html.twig`, this.generateAgentResultTemplate(moduleName), 'other'));
|
|
127
|
+
files.push(this.createFile(`${moduleName}/templates/agent-execute-form.html.twig`, this.generateExecuteFormTemplate(moduleName), 'other'));
|
|
128
|
+
// ===================================================================
|
|
129
|
+
// Documentation
|
|
130
|
+
// ===================================================================
|
|
131
|
+
files.push(this.createFile(`${moduleName}/README.md`, this.generateReadme(manifest, moduleName, opts), 'documentation'));
|
|
132
|
+
files.push(this.createFile(`${moduleName}/INSTALL.md`, this.generateInstallGuide(manifest, moduleName), 'documentation'));
|
|
133
|
+
// ===================================================================
|
|
134
|
+
// Original OSSA Manifest
|
|
135
|
+
// ===================================================================
|
|
136
|
+
files.push(this.createFile(`${moduleName}/config/ossa/agent.ossa.yaml`, JSON.stringify(manifest, null, 2), 'config'));
|
|
137
|
+
return this.createResult(true, files, undefined, {
|
|
138
|
+
duration: Date.now() - startTime,
|
|
139
|
+
version: '1.0.0',
|
|
140
|
+
moduleName,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
return this.createResult(false, [], error instanceof Error ? error.message : String(error), { duration: Date.now() - startTime });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Validate manifest for Drupal compatibility
|
|
149
|
+
*/
|
|
150
|
+
async validate(manifest) {
|
|
151
|
+
const errors = [];
|
|
152
|
+
const warnings = [];
|
|
153
|
+
// Base validation
|
|
154
|
+
const baseValidation = await super.validate(manifest);
|
|
155
|
+
if (baseValidation.errors)
|
|
156
|
+
errors.push(...baseValidation.errors);
|
|
157
|
+
if (baseValidation.warnings)
|
|
158
|
+
warnings.push(...baseValidation.warnings);
|
|
159
|
+
// Drupal-specific validation
|
|
160
|
+
const name = manifest.metadata?.name;
|
|
161
|
+
if (name && !/^[a-z0-9_]+$/.test(name)) {
|
|
162
|
+
warnings.push({
|
|
163
|
+
message: 'Module name should only contain lowercase letters, numbers, and underscores',
|
|
164
|
+
path: 'metadata.name',
|
|
165
|
+
suggestion: `Use: ${this.sanitizeModuleName(name)}`,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
valid: errors.length === 0,
|
|
170
|
+
errors: errors.length > 0 ? errors : undefined,
|
|
171
|
+
warnings: warnings.length > 0 ? warnings : undefined,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Get example manifest optimized for Drupal
|
|
176
|
+
*/
|
|
177
|
+
getExample() {
|
|
178
|
+
return {
|
|
179
|
+
apiVersion: 'ossa/v{{VERSION}}',
|
|
180
|
+
kind: 'Agent',
|
|
181
|
+
metadata: {
|
|
182
|
+
name: 'content_moderator',
|
|
183
|
+
version: '1.0.0',
|
|
184
|
+
description: 'AI-powered content moderation agent for Drupal',
|
|
185
|
+
},
|
|
186
|
+
spec: {
|
|
187
|
+
role: 'Review and moderate user-generated content for quality and compliance',
|
|
188
|
+
llm: {
|
|
189
|
+
provider: 'anthropic',
|
|
190
|
+
model: 'claude-sonnet-4-20250514',
|
|
191
|
+
temperature: 0.7,
|
|
192
|
+
maxTokens: 2048,
|
|
193
|
+
},
|
|
194
|
+
capabilities: [
|
|
195
|
+
'content-analysis',
|
|
196
|
+
'spam-detection',
|
|
197
|
+
'sentiment-analysis',
|
|
198
|
+
'auto-moderation',
|
|
199
|
+
],
|
|
200
|
+
tools: [
|
|
201
|
+
{
|
|
202
|
+
type: 'api',
|
|
203
|
+
name: 'analyze_content',
|
|
204
|
+
description: 'Analyze content for spam, toxicity, and quality',
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
type: 'api',
|
|
208
|
+
name: 'moderate_node',
|
|
209
|
+
description: 'Publish, unpublish, or flag a Drupal node',
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
// ===================================================================
|
|
216
|
+
// Generator Methods
|
|
217
|
+
// ===================================================================
|
|
218
|
+
/**
|
|
219
|
+
* Generate MODULE.info.yml
|
|
220
|
+
*/
|
|
221
|
+
generateInfoYml(manifest, moduleName, options) {
|
|
222
|
+
const dependencies = ['key_value', 'typed_data'];
|
|
223
|
+
if (options.includeEntity) {
|
|
224
|
+
dependencies.push('views');
|
|
225
|
+
}
|
|
226
|
+
return `name: '${manifest.metadata?.name || moduleName}'
|
|
227
|
+
type: module
|
|
228
|
+
description: '${manifest.metadata?.description || 'OSSA agent module'}'
|
|
229
|
+
core_version_requirement: ${options.coreVersion}
|
|
230
|
+
package: 'OSSA Agents'
|
|
231
|
+
|
|
232
|
+
dependencies:
|
|
233
|
+
${dependencies.map((d) => ` - drupal:${d}`).join('\n')}
|
|
234
|
+
|
|
235
|
+
# OSSA metadata
|
|
236
|
+
ossa:
|
|
237
|
+
version: '${manifest.metadata?.version || '1.0.0'}'
|
|
238
|
+
api_version: '${manifest.apiVersion || 'ossa/v{{VERSION}}'}'
|
|
239
|
+
kind: '${manifest.kind || 'Agent'}'
|
|
240
|
+
symfony_bundle: 'ossa/symfony-bundle'
|
|
241
|
+
`;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Generate MODULE.services.yml with full DI configuration
|
|
245
|
+
*/
|
|
246
|
+
generateServicesYml(manifest, moduleName, className, options) {
|
|
247
|
+
let services = `services:
|
|
248
|
+
# ===================================================================
|
|
249
|
+
# Agent Executor Service (wraps ossa/symfony-bundle)
|
|
250
|
+
# ===================================================================
|
|
251
|
+
|
|
252
|
+
${moduleName}.agent_executor:
|
|
253
|
+
class: Drupal\\${moduleName}\\Service\\AgentExecutorService
|
|
254
|
+
arguments:
|
|
255
|
+
- '@Ossa\\SymfonyBundle\\Agent\\AgentExecutor'
|
|
256
|
+
- '@logger.factory'
|
|
257
|
+
- '@config.factory'
|
|
258
|
+
- '@entity_type.manager'
|
|
259
|
+
`;
|
|
260
|
+
if (options.includeEntity) {
|
|
261
|
+
services += ` - '@queue'
|
|
262
|
+
`;
|
|
263
|
+
}
|
|
264
|
+
services += ` tags:
|
|
265
|
+
- { name: ossa_agent }
|
|
266
|
+
`;
|
|
267
|
+
if (options.includeQueueWorker) {
|
|
268
|
+
services += `
|
|
269
|
+
# ===================================================================
|
|
270
|
+
# Queue Service
|
|
271
|
+
# ===================================================================
|
|
272
|
+
|
|
273
|
+
${moduleName}.queue:
|
|
274
|
+
parent: queue
|
|
275
|
+
arguments: ['${moduleName}_agent_queue']
|
|
276
|
+
`;
|
|
277
|
+
}
|
|
278
|
+
return services;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Generate composer.json with ossa/symfony-bundle dependency
|
|
282
|
+
*/
|
|
283
|
+
generateComposerJson(manifest, moduleName) {
|
|
284
|
+
return JSON.stringify({
|
|
285
|
+
name: `drupal/${moduleName}`,
|
|
286
|
+
type: 'drupal-module',
|
|
287
|
+
description: manifest.metadata?.description || 'OSSA agent module',
|
|
288
|
+
keywords: ['Drupal', 'OSSA', 'AI', 'Agent', 'Symfony'],
|
|
289
|
+
license: manifest.metadata?.license || 'GPL-2.0-or-later',
|
|
290
|
+
require: {
|
|
291
|
+
'php': '>=8.2',
|
|
292
|
+
'drupal/core': '^10 || ^11',
|
|
293
|
+
'ossa/symfony-bundle': '^0.3',
|
|
294
|
+
},
|
|
295
|
+
autoload: {
|
|
296
|
+
'psr-4': {
|
|
297
|
+
[`Drupal\\${moduleName}\\`]: 'src/',
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
extra: {
|
|
301
|
+
ossa: {
|
|
302
|
+
version: manifest.metadata?.version,
|
|
303
|
+
apiVersion: manifest.apiVersion,
|
|
304
|
+
kind: manifest.kind,
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
}, null, 2);
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Generate MODULE.module with Drupal hooks
|
|
311
|
+
*/
|
|
312
|
+
generateModuleHooks(manifest, moduleName, className) {
|
|
313
|
+
return `<?php
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* @file
|
|
317
|
+
* ${className} module hooks.
|
|
318
|
+
*
|
|
319
|
+
* Provides integration hooks for OSSA agent execution within Drupal.
|
|
320
|
+
*/
|
|
321
|
+
|
|
322
|
+
use Drupal\\Core\\Entity\\EntityInterface;
|
|
323
|
+
use Drupal\\Core\\Routing\\RouteMatchInterface;
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Implements hook_help().
|
|
327
|
+
*/
|
|
328
|
+
function ${moduleName}_help($route_name, RouteMatchInterface $route_match) {
|
|
329
|
+
switch ($route_name) {
|
|
330
|
+
case 'help.page.${moduleName}':
|
|
331
|
+
return '<p>' . t('${manifest.metadata?.description || 'OSSA agent module'}') . '</p>';
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Implements hook_cron().
|
|
337
|
+
*
|
|
338
|
+
* Process queued agent tasks.
|
|
339
|
+
*/
|
|
340
|
+
function ${moduleName}_cron() {
|
|
341
|
+
// Process agent queue items
|
|
342
|
+
$queue = \\Drupal::queue('${moduleName}_agent_queue');
|
|
343
|
+
$queue_worker = \\Drupal::service('plugin.manager.queue_worker')
|
|
344
|
+
->createInstance('${moduleName}_agent_queue');
|
|
345
|
+
|
|
346
|
+
$processed = 0;
|
|
347
|
+
$max_items = 50;
|
|
348
|
+
|
|
349
|
+
while ($processed < $max_items && $item = $queue->claimItem()) {
|
|
350
|
+
try {
|
|
351
|
+
$queue_worker->processItem($item->data);
|
|
352
|
+
$queue->deleteItem($item);
|
|
353
|
+
$processed++;
|
|
354
|
+
}
|
|
355
|
+
catch (\\Exception $e) {
|
|
356
|
+
\\Drupal::logger('${moduleName}')->error('Queue processing failed: @message', [
|
|
357
|
+
'@message' => $e->getMessage(),
|
|
358
|
+
]);
|
|
359
|
+
|
|
360
|
+
// Re-queue with delay
|
|
361
|
+
$queue->releaseItem($item);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if ($processed > 0) {
|
|
366
|
+
\\Drupal::logger('${moduleName}')->info('Processed @count agent queue items', [
|
|
367
|
+
'@count' => $processed,
|
|
368
|
+
]);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Implements hook_entity_presave().
|
|
374
|
+
*
|
|
375
|
+
* Trigger agent execution on entity save (optional - configure via settings).
|
|
376
|
+
*/
|
|
377
|
+
function ${moduleName}_entity_presave(EntityInterface $entity) {
|
|
378
|
+
$config = \\Drupal::config('${moduleName}.settings');
|
|
379
|
+
|
|
380
|
+
if (!$config->get('auto_execute_on_save')) {
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Only process configured entity types
|
|
385
|
+
$enabled_types = $config->get('enabled_entity_types') ?: [];
|
|
386
|
+
if (!in_array($entity->getEntityTypeId(), $enabled_types)) {
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Queue agent execution
|
|
391
|
+
$queue = \\Drupal::queue('${moduleName}_agent_queue');
|
|
392
|
+
$queue->createItem([
|
|
393
|
+
'entity_type' => $entity->getEntityTypeId(),
|
|
394
|
+
'entity_id' => $entity->id(),
|
|
395
|
+
'operation' => 'presave',
|
|
396
|
+
'timestamp' => time(),
|
|
397
|
+
]);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Implements hook_theme().
|
|
402
|
+
*/
|
|
403
|
+
function ${moduleName}_theme($existing, $type, $theme, $path) {
|
|
404
|
+
return [
|
|
405
|
+
'agent_result' => [
|
|
406
|
+
'variables' => [
|
|
407
|
+
'result' => NULL,
|
|
408
|
+
'metadata' => NULL,
|
|
409
|
+
],
|
|
410
|
+
'template' => 'agent-result',
|
|
411
|
+
],
|
|
412
|
+
'agent_execute_form' => [
|
|
413
|
+
'render element' => 'form',
|
|
414
|
+
'template' => 'agent-execute-form',
|
|
415
|
+
],
|
|
416
|
+
];
|
|
417
|
+
}
|
|
418
|
+
`;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Generate src/Service/AgentExecutorService.php
|
|
422
|
+
*
|
|
423
|
+
* Wraps Symfony bundle AgentExecutor with Drupal-specific features
|
|
424
|
+
*/
|
|
425
|
+
generateAgentExecutorService(manifest, moduleName, className) {
|
|
426
|
+
return `<?php
|
|
427
|
+
|
|
428
|
+
namespace Drupal\\${moduleName}\\Service;
|
|
429
|
+
|
|
430
|
+
use Drupal\\Core\\Config\\ConfigFactoryInterface;
|
|
431
|
+
use Drupal\\Core\\Entity\\EntityTypeManagerInterface;
|
|
432
|
+
use Drupal\\Core\\Logger\\LoggerChannelFactoryInterface;
|
|
433
|
+
use Drupal\\Core\\Queue\\QueueFactory;
|
|
434
|
+
use Ossa\\SymfonyBundle\\Agent\\AgentExecutor;
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Agent Executor Service.
|
|
438
|
+
*
|
|
439
|
+
* Wraps the OSSA Symfony bundle AgentExecutor with Drupal-specific features:
|
|
440
|
+
* - Entity storage for results
|
|
441
|
+
* - Queue integration for async execution
|
|
442
|
+
* - Drupal configuration integration
|
|
443
|
+
* - Logging integration
|
|
444
|
+
*/
|
|
445
|
+
class AgentExecutorService {
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* The OSSA agent executor (from symfony-bundle).
|
|
449
|
+
*
|
|
450
|
+
* @var \\Ossa\\SymfonyBundle\\Agent\\AgentExecutor
|
|
451
|
+
*/
|
|
452
|
+
protected AgentExecutor $agentExecutor;
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* The logger factory.
|
|
456
|
+
*
|
|
457
|
+
* @var \\Drupal\\Core\\Logger\\LoggerChannelFactoryInterface
|
|
458
|
+
*/
|
|
459
|
+
protected LoggerChannelFactoryInterface $loggerFactory;
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* The config factory.
|
|
463
|
+
*
|
|
464
|
+
* @var \\Drupal\\Core\\Config\\ConfigFactoryInterface
|
|
465
|
+
*/
|
|
466
|
+
protected ConfigFactoryInterface $configFactory;
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* The entity type manager.
|
|
470
|
+
*
|
|
471
|
+
* @var \\Drupal\\Core\\Entity\\EntityTypeManagerInterface
|
|
472
|
+
*/
|
|
473
|
+
protected EntityTypeManagerInterface $entityTypeManager;
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* The queue factory.
|
|
477
|
+
*
|
|
478
|
+
* @var \\Drupal\\Core\\Queue\\QueueFactory
|
|
479
|
+
*/
|
|
480
|
+
protected QueueFactory $queueFactory;
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Constructs a new AgentExecutorService.
|
|
484
|
+
*/
|
|
485
|
+
public function __construct(
|
|
486
|
+
AgentExecutor $agent_executor,
|
|
487
|
+
LoggerChannelFactoryInterface $logger_factory,
|
|
488
|
+
ConfigFactoryInterface $config_factory,
|
|
489
|
+
EntityTypeManagerInterface $entity_type_manager,
|
|
490
|
+
QueueFactory $queue_factory
|
|
491
|
+
) {
|
|
492
|
+
$this->agentExecutor = $agent_executor;
|
|
493
|
+
$this->loggerFactory = $logger_factory;
|
|
494
|
+
$this->configFactory = $config_factory;
|
|
495
|
+
$this->entityTypeManager = $entity_type_manager;
|
|
496
|
+
$this->queueFactory = $queue_factory;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Execute the agent synchronously.
|
|
501
|
+
*
|
|
502
|
+
* @param string $input
|
|
503
|
+
* Input data for the agent.
|
|
504
|
+
* @param array $context
|
|
505
|
+
* Additional context (Drupal-specific: user_id, site_name, etc.).
|
|
506
|
+
* @param bool $save_result
|
|
507
|
+
* Whether to save the result to the database.
|
|
508
|
+
*
|
|
509
|
+
* @return array
|
|
510
|
+
* Agent execution result with 'success', 'output', and 'metadata' keys.
|
|
511
|
+
*/
|
|
512
|
+
public function execute(string $input, array $context = [], bool $save_result = TRUE): array {
|
|
513
|
+
$logger = $this->loggerFactory->get('${moduleName}');
|
|
514
|
+
|
|
515
|
+
try {
|
|
516
|
+
$logger->info('Agent execution started');
|
|
517
|
+
|
|
518
|
+
// Add Drupal-specific context
|
|
519
|
+
$context = $this->enrichContext($context);
|
|
520
|
+
|
|
521
|
+
// Execute via Symfony bundle
|
|
522
|
+
$response = $this->agentExecutor->execute(
|
|
523
|
+
'${manifest.metadata?.name || 'agent'}',
|
|
524
|
+
$input,
|
|
525
|
+
$context
|
|
526
|
+
);
|
|
527
|
+
|
|
528
|
+
$result = [
|
|
529
|
+
'success' => TRUE,
|
|
530
|
+
'output' => $response->getOutput(),
|
|
531
|
+
'metadata' => $response->getMetadata(),
|
|
532
|
+
];
|
|
533
|
+
|
|
534
|
+
// Save result to entity
|
|
535
|
+
if ($save_result) {
|
|
536
|
+
$this->saveResult($input, $result);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
$logger->info('Agent execution completed successfully');
|
|
540
|
+
|
|
541
|
+
return $result;
|
|
542
|
+
}
|
|
543
|
+
catch (\\Exception $e) {
|
|
544
|
+
$logger->error('Agent execution failed: @message', [
|
|
545
|
+
'@message' => $e->getMessage(),
|
|
546
|
+
]);
|
|
547
|
+
|
|
548
|
+
return [
|
|
549
|
+
'success' => FALSE,
|
|
550
|
+
'error' => $e->getMessage(),
|
|
551
|
+
];
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Execute the agent asynchronously via queue.
|
|
557
|
+
*
|
|
558
|
+
* @param string $input
|
|
559
|
+
* Input data for the agent.
|
|
560
|
+
* @param array $context
|
|
561
|
+
* Additional context.
|
|
562
|
+
*
|
|
563
|
+
* @return int
|
|
564
|
+
* Queue item ID.
|
|
565
|
+
*/
|
|
566
|
+
public function executeAsync(string $input, array $context = []): int {
|
|
567
|
+
$queue = $this->queueFactory->get('${moduleName}_agent_queue');
|
|
568
|
+
|
|
569
|
+
return $queue->createItem([
|
|
570
|
+
'input' => $input,
|
|
571
|
+
'context' => $context,
|
|
572
|
+
'timestamp' => time(),
|
|
573
|
+
]);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Enrich context with Drupal-specific data.
|
|
578
|
+
*
|
|
579
|
+
* @param array $context
|
|
580
|
+
* Base context.
|
|
581
|
+
*
|
|
582
|
+
* @return array
|
|
583
|
+
* Enriched context.
|
|
584
|
+
*/
|
|
585
|
+
protected function enrichContext(array $context): array {
|
|
586
|
+
// Add site name
|
|
587
|
+
$context['site_name'] = $this->configFactory
|
|
588
|
+
->get('system.site')
|
|
589
|
+
->get('name');
|
|
590
|
+
|
|
591
|
+
// Add current user
|
|
592
|
+
$current_user = \\Drupal::currentUser();
|
|
593
|
+
$context['user_id'] = $current_user->id();
|
|
594
|
+
$context['user_name'] = $current_user->getAccountName();
|
|
595
|
+
|
|
596
|
+
// Add Drupal version
|
|
597
|
+
$context['drupal_version'] = \\Drupal::VERSION;
|
|
598
|
+
|
|
599
|
+
// Add module configuration
|
|
600
|
+
$module_config = $this->configFactory->get('${moduleName}.settings');
|
|
601
|
+
$context['module_config'] = $module_config->getRawData();
|
|
602
|
+
|
|
603
|
+
return $context;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Save agent result to entity storage.
|
|
608
|
+
*
|
|
609
|
+
* @param string $input
|
|
610
|
+
* The input that was processed.
|
|
611
|
+
* @param array $result
|
|
612
|
+
* The execution result.
|
|
613
|
+
*/
|
|
614
|
+
protected function saveResult(string $input, array $result): void {
|
|
615
|
+
try {
|
|
616
|
+
$storage = $this->entityTypeManager->getStorage('${moduleName}_result');
|
|
617
|
+
|
|
618
|
+
$entity = $storage->create([
|
|
619
|
+
'name' => 'Result ' . date('Y-m-d H:i:s'),
|
|
620
|
+
'input' => $input,
|
|
621
|
+
'output' => $result['output'] ?? '',
|
|
622
|
+
'metadata' => json_encode($result['metadata'] ?? []),
|
|
623
|
+
'status' => $result['success'] ? 'completed' : 'failed',
|
|
624
|
+
'created' => time(),
|
|
625
|
+
]);
|
|
626
|
+
|
|
627
|
+
$entity->save();
|
|
628
|
+
}
|
|
629
|
+
catch (\\Exception $e) {
|
|
630
|
+
$this->loggerFactory->get('${moduleName}')->error(
|
|
631
|
+
'Failed to save result: @message',
|
|
632
|
+
['@message' => $e->getMessage()]
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
`;
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Generate src/Plugin/QueueWorker/AgentQueueWorker.php
|
|
641
|
+
*/
|
|
642
|
+
generateQueueWorker(manifest, moduleName, className) {
|
|
643
|
+
return `<?php
|
|
644
|
+
|
|
645
|
+
namespace Drupal\\${moduleName}\\Plugin\\QueueWorker;
|
|
646
|
+
|
|
647
|
+
use Drupal\\Core\\Queue\\QueueWorkerBase;
|
|
648
|
+
use Drupal\\Core\\Plugin\\ContainerFactoryPluginInterface;
|
|
649
|
+
use Drupal\\${moduleName}\\Service\\AgentExecutorService;
|
|
650
|
+
use Symfony\\Component\\DependencyInjection\\ContainerInterface;
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Agent Queue Worker.
|
|
654
|
+
*
|
|
655
|
+
* Processes agent execution tasks asynchronously via Drupal's queue system.
|
|
656
|
+
*
|
|
657
|
+
* @QueueWorker(
|
|
658
|
+
* id = "${moduleName}_agent_queue",
|
|
659
|
+
* title = @Translation("${className} Agent Queue Worker"),
|
|
660
|
+
* cron = {"time" = 60}
|
|
661
|
+
* )
|
|
662
|
+
*/
|
|
663
|
+
class AgentQueueWorker extends QueueWorkerBase implements ContainerFactoryPluginInterface {
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* The agent executor service.
|
|
667
|
+
*
|
|
668
|
+
* @var \\Drupal\\${moduleName}\\Service\\AgentExecutorService
|
|
669
|
+
*/
|
|
670
|
+
protected AgentExecutorService $agentExecutor;
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* {@inheritdoc}
|
|
674
|
+
*/
|
|
675
|
+
public function __construct(
|
|
676
|
+
array $configuration,
|
|
677
|
+
$plugin_id,
|
|
678
|
+
$plugin_definition,
|
|
679
|
+
AgentExecutorService $agent_executor
|
|
680
|
+
) {
|
|
681
|
+
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
|
682
|
+
$this->agentExecutor = $agent_executor;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* {@inheritdoc}
|
|
687
|
+
*/
|
|
688
|
+
public static function create(
|
|
689
|
+
ContainerInterface $container,
|
|
690
|
+
array $configuration,
|
|
691
|
+
$plugin_id,
|
|
692
|
+
$plugin_definition
|
|
693
|
+
) {
|
|
694
|
+
return new static(
|
|
695
|
+
$configuration,
|
|
696
|
+
$plugin_id,
|
|
697
|
+
$plugin_definition,
|
|
698
|
+
$container->get('${moduleName}.agent_executor')
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* {@inheritdoc}
|
|
704
|
+
*/
|
|
705
|
+
public function processItem($data) {
|
|
706
|
+
$input = $data['input'] ?? '';
|
|
707
|
+
$context = $data['context'] ?? [];
|
|
708
|
+
|
|
709
|
+
if (empty($input)) {
|
|
710
|
+
throw new \\Exception('Queue item missing required input data');
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// Execute agent
|
|
714
|
+
$result = $this->agentExecutor->execute($input, $context, TRUE);
|
|
715
|
+
|
|
716
|
+
if (!$result['success']) {
|
|
717
|
+
throw new \\Exception($result['error'] ?? 'Agent execution failed');
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
return $result;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
`;
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* Generate src/Entity/AgentResult.php
|
|
727
|
+
*/
|
|
728
|
+
generateEntityClass(manifest, moduleName, className) {
|
|
729
|
+
return `<?php
|
|
730
|
+
|
|
731
|
+
namespace Drupal\\${moduleName}\\Entity;
|
|
732
|
+
|
|
733
|
+
use Drupal\\Core\\Entity\\ContentEntityBase;
|
|
734
|
+
use Drupal\\Core\\Entity\\EntityTypeInterface;
|
|
735
|
+
use Drupal\\Core\\Field\\BaseFieldDefinition;
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* Defines the Agent Result entity.
|
|
739
|
+
*
|
|
740
|
+
* Stores agent execution results for auditing and analysis.
|
|
741
|
+
*
|
|
742
|
+
* @ContentEntityType(
|
|
743
|
+
* id = "${moduleName}_result",
|
|
744
|
+
* label = @Translation("Agent Result"),
|
|
745
|
+
* base_table = "${moduleName}_result",
|
|
746
|
+
* entity_keys = {
|
|
747
|
+
* "id" = "id",
|
|
748
|
+
* "label" = "name",
|
|
749
|
+
* "uuid" = "uuid",
|
|
750
|
+
* },
|
|
751
|
+
* handlers = {
|
|
752
|
+
* "view_builder" = "Drupal\\Core\\Entity\\EntityViewBuilder",
|
|
753
|
+
* "list_builder" = "Drupal\\Core\\Entity\\EntityListBuilder",
|
|
754
|
+
* "views_data" = "Drupal\\views\\EntityViewsData",
|
|
755
|
+
* "access" = "Drupal\\Core\\Entity\\EntityAccessControlHandler",
|
|
756
|
+
* },
|
|
757
|
+
* links = {
|
|
758
|
+
* "canonical" = "/admin/${moduleName}/result/{${moduleName}_result}",
|
|
759
|
+
* "collection" = "/admin/${moduleName}/results",
|
|
760
|
+
* },
|
|
761
|
+
* )
|
|
762
|
+
*/
|
|
763
|
+
class AgentResult extends ContentEntityBase implements AgentResultInterface {
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* {@inheritdoc}
|
|
767
|
+
*/
|
|
768
|
+
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
|
|
769
|
+
$fields = parent::baseFieldDefinitions($entity_type);
|
|
770
|
+
|
|
771
|
+
$fields['name'] = BaseFieldDefinition::create('string')
|
|
772
|
+
->setLabel(t('Name'))
|
|
773
|
+
->setDescription(t('Result name/title'))
|
|
774
|
+
->setSettings([
|
|
775
|
+
'max_length' => 255,
|
|
776
|
+
'text_processing' => 0,
|
|
777
|
+
])
|
|
778
|
+
->setDisplayOptions('view', [
|
|
779
|
+
'label' => 'hidden',
|
|
780
|
+
'type' => 'string',
|
|
781
|
+
'weight' => -5,
|
|
782
|
+
])
|
|
783
|
+
->setDisplayOptions('form', [
|
|
784
|
+
'type' => 'string_textfield',
|
|
785
|
+
'weight' => -5,
|
|
786
|
+
]);
|
|
787
|
+
|
|
788
|
+
$fields['input'] = BaseFieldDefinition::create('string_long')
|
|
789
|
+
->setLabel(t('Input'))
|
|
790
|
+
->setDescription(t('Agent input data'))
|
|
791
|
+
->setDisplayOptions('view', [
|
|
792
|
+
'label' => 'above',
|
|
793
|
+
'type' => 'text_default',
|
|
794
|
+
'weight' => 0,
|
|
795
|
+
]);
|
|
796
|
+
|
|
797
|
+
$fields['output'] = BaseFieldDefinition::create('string_long')
|
|
798
|
+
->setLabel(t('Output'))
|
|
799
|
+
->setDescription(t('Agent output/response'))
|
|
800
|
+
->setDisplayOptions('view', [
|
|
801
|
+
'label' => 'above',
|
|
802
|
+
'type' => 'text_default',
|
|
803
|
+
'weight' => 1,
|
|
804
|
+
]);
|
|
805
|
+
|
|
806
|
+
$fields['metadata'] = BaseFieldDefinition::create('string_long')
|
|
807
|
+
->setLabel(t('Metadata'))
|
|
808
|
+
->setDescription(t('Execution metadata (JSON)'))
|
|
809
|
+
->setDisplayOptions('view', [
|
|
810
|
+
'label' => 'above',
|
|
811
|
+
'type' => 'text_default',
|
|
812
|
+
'weight' => 2,
|
|
813
|
+
]);
|
|
814
|
+
|
|
815
|
+
$fields['status'] = BaseFieldDefinition::create('list_string')
|
|
816
|
+
->setLabel(t('Status'))
|
|
817
|
+
->setSettings([
|
|
818
|
+
'allowed_values' => [
|
|
819
|
+
'pending' => 'Pending',
|
|
820
|
+
'processing' => 'Processing',
|
|
821
|
+
'completed' => 'Completed',
|
|
822
|
+
'failed' => 'Failed',
|
|
823
|
+
],
|
|
824
|
+
])
|
|
825
|
+
->setDefaultValue('pending')
|
|
826
|
+
->setDisplayOptions('view', [
|
|
827
|
+
'label' => 'inline',
|
|
828
|
+
'type' => 'list_default',
|
|
829
|
+
'weight' => 3,
|
|
830
|
+
]);
|
|
831
|
+
|
|
832
|
+
$fields['created'] = BaseFieldDefinition::create('created')
|
|
833
|
+
->setLabel(t('Created'))
|
|
834
|
+
->setDescription(t('Creation timestamp'));
|
|
835
|
+
|
|
836
|
+
return $fields;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
`;
|
|
840
|
+
}
|
|
841
|
+
/**
|
|
842
|
+
* Generate src/Entity/AgentResultInterface.php
|
|
843
|
+
*/
|
|
844
|
+
generateEntityInterface(moduleName) {
|
|
845
|
+
return `<?php
|
|
846
|
+
|
|
847
|
+
namespace Drupal\\${moduleName}\\Entity;
|
|
848
|
+
|
|
849
|
+
use Drupal\\Core\\Entity\\ContentEntityInterface;
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* Interface for Agent Result entities.
|
|
853
|
+
*/
|
|
854
|
+
interface AgentResultInterface extends ContentEntityInterface {
|
|
855
|
+
}
|
|
856
|
+
`;
|
|
857
|
+
}
|
|
858
|
+
/**
|
|
859
|
+
* Generate MODULE.views.inc
|
|
860
|
+
*/
|
|
861
|
+
generateViewsData(moduleName, className) {
|
|
862
|
+
return `<?php
|
|
863
|
+
|
|
864
|
+
/**
|
|
865
|
+
* @file
|
|
866
|
+
* Provide views data for ${moduleName}_result entities.
|
|
867
|
+
*/
|
|
868
|
+
|
|
869
|
+
/**
|
|
870
|
+
* Implements hook_views_data().
|
|
871
|
+
*/
|
|
872
|
+
function ${moduleName}_views_data() {
|
|
873
|
+
$data = [];
|
|
874
|
+
|
|
875
|
+
$data['${moduleName}_result']['table']['group'] = t('Agent Result');
|
|
876
|
+
$data['${moduleName}_result']['table']['base'] = [
|
|
877
|
+
'field' => 'id',
|
|
878
|
+
'title' => t('Agent Result'),
|
|
879
|
+
'help' => t('Agent execution results.'),
|
|
880
|
+
];
|
|
881
|
+
|
|
882
|
+
$data['${moduleName}_result']['id'] = [
|
|
883
|
+
'title' => t('ID'),
|
|
884
|
+
'help' => t('The agent result ID.'),
|
|
885
|
+
'field' => [
|
|
886
|
+
'id' => 'numeric',
|
|
887
|
+
],
|
|
888
|
+
'sort' => [
|
|
889
|
+
'id' => 'standard',
|
|
890
|
+
],
|
|
891
|
+
'filter' => [
|
|
892
|
+
'id' => 'numeric',
|
|
893
|
+
],
|
|
894
|
+
];
|
|
895
|
+
|
|
896
|
+
$data['${moduleName}_result']['name'] = [
|
|
897
|
+
'title' => t('Name'),
|
|
898
|
+
'help' => t('The result name.'),
|
|
899
|
+
'field' => [
|
|
900
|
+
'id' => 'standard',
|
|
901
|
+
],
|
|
902
|
+
'sort' => [
|
|
903
|
+
'id' => 'standard',
|
|
904
|
+
],
|
|
905
|
+
'filter' => [
|
|
906
|
+
'id' => 'string',
|
|
907
|
+
],
|
|
908
|
+
];
|
|
909
|
+
|
|
910
|
+
$data['${moduleName}_result']['status'] = [
|
|
911
|
+
'title' => t('Status'),
|
|
912
|
+
'help' => t('The execution status.'),
|
|
913
|
+
'field' => [
|
|
914
|
+
'id' => 'standard',
|
|
915
|
+
],
|
|
916
|
+
'sort' => [
|
|
917
|
+
'id' => 'standard',
|
|
918
|
+
],
|
|
919
|
+
'filter' => [
|
|
920
|
+
'id' => 'string',
|
|
921
|
+
],
|
|
922
|
+
];
|
|
923
|
+
|
|
924
|
+
$data['${moduleName}_result']['created'] = [
|
|
925
|
+
'title' => t('Created'),
|
|
926
|
+
'help' => t('The creation timestamp.'),
|
|
927
|
+
'field' => [
|
|
928
|
+
'id' => 'date',
|
|
929
|
+
],
|
|
930
|
+
'sort' => [
|
|
931
|
+
'id' => 'date',
|
|
932
|
+
],
|
|
933
|
+
'filter' => [
|
|
934
|
+
'id' => 'date',
|
|
935
|
+
],
|
|
936
|
+
];
|
|
937
|
+
|
|
938
|
+
return $data;
|
|
939
|
+
}
|
|
940
|
+
`;
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Generate src/Controller/AgentController.php
|
|
944
|
+
*/
|
|
945
|
+
generateController(manifest, moduleName, className) {
|
|
946
|
+
return `<?php
|
|
947
|
+
|
|
948
|
+
namespace Drupal\\${moduleName}\\Controller;
|
|
949
|
+
|
|
950
|
+
use Drupal\\Core\\Controller\\ControllerBase;
|
|
951
|
+
use Drupal\\${moduleName}\\Service\\AgentExecutorService;
|
|
952
|
+
use Symfony\\Component\\DependencyInjection\\ContainerInterface;
|
|
953
|
+
use Symfony\\Component\\HttpFoundation\\JsonResponse;
|
|
954
|
+
use Symfony\\Component\\HttpFoundation\\Request;
|
|
955
|
+
|
|
956
|
+
/**
|
|
957
|
+
* Agent Controller.
|
|
958
|
+
*
|
|
959
|
+
* Provides admin UI and API endpoints for agent execution.
|
|
960
|
+
*/
|
|
961
|
+
class AgentController extends ControllerBase {
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* The agent executor service.
|
|
965
|
+
*
|
|
966
|
+
* @var \\Drupal\\${moduleName}\\Service\\AgentExecutorService
|
|
967
|
+
*/
|
|
968
|
+
protected AgentExecutorService $agentExecutor;
|
|
969
|
+
|
|
970
|
+
/**
|
|
971
|
+
* {@inheritdoc}
|
|
972
|
+
*/
|
|
973
|
+
public function __construct(AgentExecutorService $agent_executor) {
|
|
974
|
+
$this->agentExecutor = $agent_executor;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
/**
|
|
978
|
+
* {@inheritdoc}
|
|
979
|
+
*/
|
|
980
|
+
public static function create(ContainerInterface $container) {
|
|
981
|
+
return new static(
|
|
982
|
+
$container->get('${moduleName}.agent_executor')
|
|
983
|
+
);
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
/**
|
|
987
|
+
* Execute agent via UI.
|
|
988
|
+
*/
|
|
989
|
+
public function executePage() {
|
|
990
|
+
$form = \\Drupal::formBuilder()->getForm('Drupal\\${moduleName}\\Form\\AgentExecuteForm');
|
|
991
|
+
|
|
992
|
+
return [
|
|
993
|
+
'#theme' => 'agent_execute_form',
|
|
994
|
+
'#form' => $form,
|
|
995
|
+
];
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
/**
|
|
999
|
+
* Execute agent via API.
|
|
1000
|
+
*/
|
|
1001
|
+
public function executeApi(Request $request): JsonResponse {
|
|
1002
|
+
$data = json_decode($request->getContent(), TRUE);
|
|
1003
|
+
|
|
1004
|
+
if (empty($data['input'])) {
|
|
1005
|
+
return new JsonResponse([
|
|
1006
|
+
'success' => FALSE,
|
|
1007
|
+
'error' => 'Missing required field: input',
|
|
1008
|
+
], 400);
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
$result = $this->agentExecutor->execute(
|
|
1012
|
+
$data['input'],
|
|
1013
|
+
$data['context'] ?? [],
|
|
1014
|
+
$data['save_result'] ?? TRUE
|
|
1015
|
+
);
|
|
1016
|
+
|
|
1017
|
+
return new JsonResponse($result);
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
/**
|
|
1021
|
+
* Execute agent asynchronously via API.
|
|
1022
|
+
*/
|
|
1023
|
+
public function executeAsyncApi(Request $request): JsonResponse {
|
|
1024
|
+
$data = json_decode($request->getContent(), TRUE);
|
|
1025
|
+
|
|
1026
|
+
if (empty($data['input'])) {
|
|
1027
|
+
return new JsonResponse([
|
|
1028
|
+
'success' => FALSE,
|
|
1029
|
+
'error' => 'Missing required field: input',
|
|
1030
|
+
], 400);
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
$queue_id = $this->agentExecutor->executeAsync(
|
|
1034
|
+
$data['input'],
|
|
1035
|
+
$data['context'] ?? []
|
|
1036
|
+
);
|
|
1037
|
+
|
|
1038
|
+
return new JsonResponse([
|
|
1039
|
+
'success' => TRUE,
|
|
1040
|
+
'queue_id' => $queue_id,
|
|
1041
|
+
'message' => 'Agent execution queued',
|
|
1042
|
+
]);
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
/**
|
|
1046
|
+
* Results listing page.
|
|
1047
|
+
*/
|
|
1048
|
+
public function resultsPage() {
|
|
1049
|
+
$storage = $this->entityTypeManager()->getStorage('${moduleName}_result');
|
|
1050
|
+
$results = $storage->loadMultiple();
|
|
1051
|
+
|
|
1052
|
+
$rows = [];
|
|
1053
|
+
foreach ($results as $result) {
|
|
1054
|
+
$rows[] = [
|
|
1055
|
+
'id' => $result->id(),
|
|
1056
|
+
'name' => $result->get('name')->value,
|
|
1057
|
+
'status' => $result->get('status')->value,
|
|
1058
|
+
'created' => date('Y-m-d H:i:s', $result->get('created')->value),
|
|
1059
|
+
];
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
return [
|
|
1063
|
+
'#theme' => 'table',
|
|
1064
|
+
'#header' => ['ID', 'Name', 'Status', 'Created'],
|
|
1065
|
+
'#rows' => $rows,
|
|
1066
|
+
'#empty' => $this->t('No results found.'),
|
|
1067
|
+
];
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
`;
|
|
1071
|
+
}
|
|
1072
|
+
/**
|
|
1073
|
+
* Generate MODULE.routing.yml
|
|
1074
|
+
*/
|
|
1075
|
+
generateRouting(moduleName) {
|
|
1076
|
+
return `${moduleName}.execute:
|
|
1077
|
+
path: '/admin/${moduleName}/execute'
|
|
1078
|
+
defaults:
|
|
1079
|
+
_controller: '\\Drupal\\${moduleName}\\Controller\\AgentController::executePage'
|
|
1080
|
+
_title: 'Execute Agent'
|
|
1081
|
+
requirements:
|
|
1082
|
+
_permission: 'administer ${moduleName}'
|
|
1083
|
+
|
|
1084
|
+
${moduleName}.api.execute:
|
|
1085
|
+
path: '/api/${moduleName}/execute'
|
|
1086
|
+
defaults:
|
|
1087
|
+
_controller: '\\Drupal\\${moduleName}\\Controller\\AgentController::executeApi'
|
|
1088
|
+
methods: [POST]
|
|
1089
|
+
requirements:
|
|
1090
|
+
_permission: 'access content'
|
|
1091
|
+
|
|
1092
|
+
${moduleName}.api.execute_async:
|
|
1093
|
+
path: '/api/${moduleName}/execute-async'
|
|
1094
|
+
defaults:
|
|
1095
|
+
_controller: '\\Drupal\\${moduleName}\\Controller\\AgentController::executeAsyncApi'
|
|
1096
|
+
methods: [POST]
|
|
1097
|
+
requirements:
|
|
1098
|
+
_permission: 'access content'
|
|
1099
|
+
|
|
1100
|
+
${moduleName}.results:
|
|
1101
|
+
path: '/admin/${moduleName}/results'
|
|
1102
|
+
defaults:
|
|
1103
|
+
_controller: '\\Drupal\\${moduleName}\\Controller\\AgentController::resultsPage'
|
|
1104
|
+
_title: 'Agent Results'
|
|
1105
|
+
requirements:
|
|
1106
|
+
_permission: 'administer ${moduleName}'
|
|
1107
|
+
|
|
1108
|
+
${moduleName}.settings:
|
|
1109
|
+
path: '/admin/config/${moduleName}'
|
|
1110
|
+
defaults:
|
|
1111
|
+
_form: '\\Drupal\\${moduleName}\\Form\\AgentConfigForm'
|
|
1112
|
+
_title: 'Agent Configuration'
|
|
1113
|
+
requirements:
|
|
1114
|
+
_permission: 'administer ${moduleName}'
|
|
1115
|
+
`;
|
|
1116
|
+
}
|
|
1117
|
+
/**
|
|
1118
|
+
* Generate src/Form/AgentConfigForm.php
|
|
1119
|
+
*/
|
|
1120
|
+
generateConfigForm(manifest, moduleName, className) {
|
|
1121
|
+
return `<?php
|
|
1122
|
+
|
|
1123
|
+
namespace Drupal\\${moduleName}\\Form;
|
|
1124
|
+
|
|
1125
|
+
use Drupal\\Core\\Form\\ConfigFormBase;
|
|
1126
|
+
use Drupal\\Core\\Form\\FormStateInterface;
|
|
1127
|
+
|
|
1128
|
+
/**
|
|
1129
|
+
* Configuration form for ${className} agent.
|
|
1130
|
+
*/
|
|
1131
|
+
class AgentConfigForm extends ConfigFormBase {
|
|
1132
|
+
|
|
1133
|
+
/**
|
|
1134
|
+
* {@inheritdoc}
|
|
1135
|
+
*/
|
|
1136
|
+
protected function getEditableConfigNames() {
|
|
1137
|
+
return ['${moduleName}.settings'];
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
/**
|
|
1141
|
+
* {@inheritdoc}
|
|
1142
|
+
*/
|
|
1143
|
+
public function getFormId() {
|
|
1144
|
+
return '${moduleName}_config_form';
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
/**
|
|
1148
|
+
* {@inheritdoc}
|
|
1149
|
+
*/
|
|
1150
|
+
public function buildForm(array $form, FormStateInterface $form_state) {
|
|
1151
|
+
$config = $this->config('${moduleName}.settings');
|
|
1152
|
+
|
|
1153
|
+
$form['auto_execute_on_save'] = [
|
|
1154
|
+
'#type' => 'checkbox',
|
|
1155
|
+
'#title' => $this->t('Auto-execute on entity save'),
|
|
1156
|
+
'#description' => $this->t('Automatically execute agent when configured entities are saved.'),
|
|
1157
|
+
'#default_value' => $config->get('auto_execute_on_save') ?? FALSE,
|
|
1158
|
+
];
|
|
1159
|
+
|
|
1160
|
+
$form['enabled_entity_types'] = [
|
|
1161
|
+
'#type' => 'checkboxes',
|
|
1162
|
+
'#title' => $this->t('Enabled entity types'),
|
|
1163
|
+
'#description' => $this->t('Entity types that trigger agent execution.'),
|
|
1164
|
+
'#options' => [
|
|
1165
|
+
'node' => $this->t('Content'),
|
|
1166
|
+
'comment' => $this->t('Comment'),
|
|
1167
|
+
'user' => $this->t('User'),
|
|
1168
|
+
],
|
|
1169
|
+
'#default_value' => $config->get('enabled_entity_types') ?: [],
|
|
1170
|
+
'#states' => [
|
|
1171
|
+
'visible' => [
|
|
1172
|
+
':input[name="auto_execute_on_save"]' => ['checked' => TRUE],
|
|
1173
|
+
],
|
|
1174
|
+
],
|
|
1175
|
+
];
|
|
1176
|
+
|
|
1177
|
+
$form['llm_provider'] = [
|
|
1178
|
+
'#type' => 'select',
|
|
1179
|
+
'#title' => $this->t('LLM Provider'),
|
|
1180
|
+
'#options' => [
|
|
1181
|
+
'anthropic' => $this->t('Anthropic (Claude)'),
|
|
1182
|
+
'openai' => $this->t('OpenAI (GPT)'),
|
|
1183
|
+
'google' => $this->t('Google (Gemini)'),
|
|
1184
|
+
'azure' => $this->t('Azure OpenAI'),
|
|
1185
|
+
],
|
|
1186
|
+
'#default_value' => $config->get('llm_provider') ?? 'anthropic',
|
|
1187
|
+
];
|
|
1188
|
+
|
|
1189
|
+
$form['llm_model'] = [
|
|
1190
|
+
'#type' => 'textfield',
|
|
1191
|
+
'#title' => $this->t('LLM Model'),
|
|
1192
|
+
'#default_value' => $config->get('llm_model') ?? 'claude-sonnet-4-20250514',
|
|
1193
|
+
];
|
|
1194
|
+
|
|
1195
|
+
$form['temperature'] = [
|
|
1196
|
+
'#type' => 'number',
|
|
1197
|
+
'#title' => $this->t('Temperature'),
|
|
1198
|
+
'#description' => $this->t('Controls randomness (0.0 to 1.0).'),
|
|
1199
|
+
'#min' => 0,
|
|
1200
|
+
'#max' => 1,
|
|
1201
|
+
'#step' => 0.1,
|
|
1202
|
+
'#default_value' => $config->get('temperature') ?? 0.7,
|
|
1203
|
+
];
|
|
1204
|
+
|
|
1205
|
+
return parent::buildForm($form, $form_state);
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
/**
|
|
1209
|
+
* {@inheritdoc}
|
|
1210
|
+
*/
|
|
1211
|
+
public function submitForm(array &$form, FormStateInterface $form_state) {
|
|
1212
|
+
$this->config('${moduleName}.settings')
|
|
1213
|
+
->set('auto_execute_on_save', $form_state->getValue('auto_execute_on_save'))
|
|
1214
|
+
->set('enabled_entity_types', array_filter($form_state->getValue('enabled_entity_types')))
|
|
1215
|
+
->set('llm_provider', $form_state->getValue('llm_provider'))
|
|
1216
|
+
->set('llm_model', $form_state->getValue('llm_model'))
|
|
1217
|
+
->set('temperature', $form_state->getValue('temperature'))
|
|
1218
|
+
->save();
|
|
1219
|
+
|
|
1220
|
+
parent::submitForm($form, $form_state);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
`;
|
|
1224
|
+
}
|
|
1225
|
+
/**
|
|
1226
|
+
* Generate MODULE.links.menu.yml
|
|
1227
|
+
*/
|
|
1228
|
+
generateMenuLinks(moduleName) {
|
|
1229
|
+
return `${moduleName}.admin:
|
|
1230
|
+
title: 'Agent'
|
|
1231
|
+
description: 'Configure agent settings'
|
|
1232
|
+
route_name: ${moduleName}.settings
|
|
1233
|
+
parent: system.admin_config
|
|
1234
|
+
weight: 100
|
|
1235
|
+
|
|
1236
|
+
${moduleName}.execute:
|
|
1237
|
+
title: 'Execute'
|
|
1238
|
+
route_name: ${moduleName}.execute
|
|
1239
|
+
parent: ${moduleName}.admin
|
|
1240
|
+
weight: 0
|
|
1241
|
+
|
|
1242
|
+
${moduleName}.results:
|
|
1243
|
+
title: 'Results'
|
|
1244
|
+
route_name: ${moduleName}.results
|
|
1245
|
+
parent: ${moduleName}.admin
|
|
1246
|
+
weight: 10
|
|
1247
|
+
`;
|
|
1248
|
+
}
|
|
1249
|
+
/**
|
|
1250
|
+
* Generate config/schema/MODULE.schema.yml
|
|
1251
|
+
*/
|
|
1252
|
+
generateConfigSchema(moduleName) {
|
|
1253
|
+
return `${moduleName}.settings:
|
|
1254
|
+
type: config_object
|
|
1255
|
+
label: 'Agent Settings'
|
|
1256
|
+
mapping:
|
|
1257
|
+
auto_execute_on_save:
|
|
1258
|
+
type: boolean
|
|
1259
|
+
label: 'Auto-execute on entity save'
|
|
1260
|
+
enabled_entity_types:
|
|
1261
|
+
type: sequence
|
|
1262
|
+
label: 'Enabled entity types'
|
|
1263
|
+
sequence:
|
|
1264
|
+
type: string
|
|
1265
|
+
llm_provider:
|
|
1266
|
+
type: string
|
|
1267
|
+
label: 'LLM Provider'
|
|
1268
|
+
llm_model:
|
|
1269
|
+
type: string
|
|
1270
|
+
label: 'LLM Model'
|
|
1271
|
+
temperature:
|
|
1272
|
+
type: float
|
|
1273
|
+
label: 'Temperature'
|
|
1274
|
+
`;
|
|
1275
|
+
}
|
|
1276
|
+
/**
|
|
1277
|
+
* Generate config/install/MODULE.settings.yml
|
|
1278
|
+
*/
|
|
1279
|
+
generateDefaultConfig(manifest) {
|
|
1280
|
+
const llmConfig = manifest.spec?.llm || {};
|
|
1281
|
+
return `auto_execute_on_save: false
|
|
1282
|
+
enabled_entity_types: []
|
|
1283
|
+
llm_provider: '${llmConfig.provider || 'anthropic'}'
|
|
1284
|
+
llm_model: '${llmConfig.model || 'claude-sonnet-4-20250514'}'
|
|
1285
|
+
temperature: ${llmConfig.temperature || 0.7}
|
|
1286
|
+
`;
|
|
1287
|
+
}
|
|
1288
|
+
/**
|
|
1289
|
+
* Generate templates/agent-result.html.twig
|
|
1290
|
+
*/
|
|
1291
|
+
generateAgentResultTemplate(moduleName) {
|
|
1292
|
+
return `{#
|
|
1293
|
+
/**
|
|
1294
|
+
* @file
|
|
1295
|
+
* Theme template for agent execution result.
|
|
1296
|
+
*
|
|
1297
|
+
* Available variables:
|
|
1298
|
+
* - result: The execution result object
|
|
1299
|
+
* - metadata: Execution metadata
|
|
1300
|
+
*/
|
|
1301
|
+
#}
|
|
1302
|
+
<div class="${moduleName}-result">
|
|
1303
|
+
<div class="result-output">
|
|
1304
|
+
<h3>{{ 'Output'|t }}</h3>
|
|
1305
|
+
<div class="output-content">
|
|
1306
|
+
{{ result.output }}
|
|
1307
|
+
</div>
|
|
1308
|
+
</div>
|
|
1309
|
+
|
|
1310
|
+
{% if metadata %}
|
|
1311
|
+
<div class="result-metadata">
|
|
1312
|
+
<h4>{{ 'Metadata'|t }}</h4>
|
|
1313
|
+
<dl>
|
|
1314
|
+
{% if metadata.duration_ms %}
|
|
1315
|
+
<dt>{{ 'Duration'|t }}</dt>
|
|
1316
|
+
<dd>{{ metadata.duration_ms }} ms</dd>
|
|
1317
|
+
{% endif %}
|
|
1318
|
+
|
|
1319
|
+
{% if metadata.model %}
|
|
1320
|
+
<dt>{{ 'Model'|t }}</dt>
|
|
1321
|
+
<dd>{{ metadata.model }}</dd>
|
|
1322
|
+
{% endif %}
|
|
1323
|
+
|
|
1324
|
+
{% if metadata.provider %}
|
|
1325
|
+
<dt>{{ 'Provider'|t }}</dt>
|
|
1326
|
+
<dd>{{ metadata.provider }}</dd>
|
|
1327
|
+
{% endif %}
|
|
1328
|
+
|
|
1329
|
+
{% if metadata.usage %}
|
|
1330
|
+
<dt>{{ 'Token Usage'|t }}</dt>
|
|
1331
|
+
<dd>{{ metadata.usage.total_tokens|default('N/A') }}</dd>
|
|
1332
|
+
{% endif %}
|
|
1333
|
+
</dl>
|
|
1334
|
+
</div>
|
|
1335
|
+
{% endif %}
|
|
1336
|
+
</div>
|
|
1337
|
+
`;
|
|
1338
|
+
}
|
|
1339
|
+
/**
|
|
1340
|
+
* Generate templates/agent-execute-form.html.twig
|
|
1341
|
+
*/
|
|
1342
|
+
generateExecuteFormTemplate(moduleName) {
|
|
1343
|
+
return `{#
|
|
1344
|
+
/**
|
|
1345
|
+
* @file
|
|
1346
|
+
* Theme template for agent execute form.
|
|
1347
|
+
*
|
|
1348
|
+
* Available variables:
|
|
1349
|
+
* - form: The form render array
|
|
1350
|
+
*/
|
|
1351
|
+
#}
|
|
1352
|
+
<div class="${moduleName}-execute-form">
|
|
1353
|
+
<div class="form-header">
|
|
1354
|
+
<h2>{{ 'Execute Agent'|t }}</h2>
|
|
1355
|
+
<p>{{ 'Enter your input and execute the agent.'|t }}</p>
|
|
1356
|
+
</div>
|
|
1357
|
+
|
|
1358
|
+
<div class="form-content">
|
|
1359
|
+
{{ form }}
|
|
1360
|
+
</div>
|
|
1361
|
+
</div>
|
|
1362
|
+
`;
|
|
1363
|
+
}
|
|
1364
|
+
/**
|
|
1365
|
+
* Generate README.md
|
|
1366
|
+
*/
|
|
1367
|
+
generateReadme(manifest, moduleName, options) {
|
|
1368
|
+
const capabilities = (manifest.spec?.capabilities || [])
|
|
1369
|
+
.map(c => typeof c === 'string' ? c : c.name || '');
|
|
1370
|
+
const tools = (manifest.spec?.tools || []);
|
|
1371
|
+
return `# ${manifest.metadata?.name || moduleName}
|
|
1372
|
+
|
|
1373
|
+
${manifest.metadata?.description || 'OSSA agent module for Drupal'}
|
|
1374
|
+
|
|
1375
|
+
## Description
|
|
1376
|
+
|
|
1377
|
+
${manifest.spec?.role || 'AI Agent powered by OSSA'}
|
|
1378
|
+
|
|
1379
|
+
This module provides a complete integration of an OSSA agent with Drupal, including:
|
|
1380
|
+
|
|
1381
|
+
${options.includeQueueWorker ? '- ✅ Queue Worker for asynchronous execution' : ''}
|
|
1382
|
+
${options.includeEntity ? '- ✅ Entity storage for agent results' : ''}
|
|
1383
|
+
${options.includeController ? '- ✅ Admin UI and API endpoints' : ''}
|
|
1384
|
+
${options.includeConfigForm ? '- ✅ Configuration form' : ''}
|
|
1385
|
+
${options.includeHooks ? '- ✅ Drupal hooks (entity_presave, cron)' : ''}
|
|
1386
|
+
${options.includeViews ? '- ✅ Views integration' : ''}
|
|
1387
|
+
|
|
1388
|
+
## Requirements
|
|
1389
|
+
|
|
1390
|
+
- **Drupal**: ${options.coreVersion}
|
|
1391
|
+
- **PHP**: >=8.2
|
|
1392
|
+
- **Composer packages**:
|
|
1393
|
+
- \`ossa/symfony-bundle\`: ^0.3
|
|
1394
|
+
|
|
1395
|
+
## Installation
|
|
1396
|
+
|
|
1397
|
+
### 1. Install via Composer
|
|
1398
|
+
|
|
1399
|
+
\`\`\`bash
|
|
1400
|
+
cd /path/to/drupal
|
|
1401
|
+
composer require ossa/symfony-bundle
|
|
1402
|
+
\`\`\`
|
|
1403
|
+
|
|
1404
|
+
### 2. Copy module to Drupal
|
|
1405
|
+
|
|
1406
|
+
\`\`\`bash
|
|
1407
|
+
cp -r ${moduleName} web/modules/custom/
|
|
1408
|
+
\`\`\`
|
|
1409
|
+
|
|
1410
|
+
### 3. Enable module
|
|
1411
|
+
|
|
1412
|
+
\`\`\`bash
|
|
1413
|
+
drush en ${moduleName}
|
|
1414
|
+
\`\`\`
|
|
1415
|
+
|
|
1416
|
+
### 4. Configure API keys
|
|
1417
|
+
|
|
1418
|
+
Set your LLM provider API keys in \`settings.php\`:
|
|
1419
|
+
|
|
1420
|
+
\`\`\`php
|
|
1421
|
+
// Anthropic (Claude)
|
|
1422
|
+
$config['ossa']['providers']['anthropic']['api_key'] = getenv('ANTHROPIC_API_KEY');
|
|
1423
|
+
|
|
1424
|
+
// OpenAI
|
|
1425
|
+
$config['ossa']['providers']['openai']['api_key'] = getenv('OPENAI_API_KEY');
|
|
1426
|
+
\`\`\`
|
|
1427
|
+
|
|
1428
|
+
Or use environment variables:
|
|
1429
|
+
|
|
1430
|
+
\`\`\`bash
|
|
1431
|
+
export ANTHROPIC_API_KEY="sk-ant-..."
|
|
1432
|
+
export OPENAI_API_KEY="sk-..."
|
|
1433
|
+
\`\`\`
|
|
1434
|
+
|
|
1435
|
+
## Configuration
|
|
1436
|
+
|
|
1437
|
+
Visit \`/admin/config/${moduleName}\` to configure:
|
|
1438
|
+
|
|
1439
|
+
- LLM provider (Anthropic, OpenAI, Google, Azure)
|
|
1440
|
+
- Model selection
|
|
1441
|
+
- Temperature settings
|
|
1442
|
+
- Auto-execution triggers
|
|
1443
|
+
- Enabled entity types
|
|
1444
|
+
|
|
1445
|
+
## Usage
|
|
1446
|
+
|
|
1447
|
+
### Execute via Admin UI
|
|
1448
|
+
|
|
1449
|
+
1. Navigate to \`/admin/${moduleName}/execute\`
|
|
1450
|
+
2. Enter your input
|
|
1451
|
+
3. Click "Execute"
|
|
1452
|
+
4. View results
|
|
1453
|
+
|
|
1454
|
+
### Execute via Drush
|
|
1455
|
+
|
|
1456
|
+
\`\`\`bash
|
|
1457
|
+
drush ossa:agent:execute ${manifest.metadata?.name || 'agent'} "Your input here"
|
|
1458
|
+
\`\`\`
|
|
1459
|
+
|
|
1460
|
+
### Execute via API
|
|
1461
|
+
|
|
1462
|
+
\`\`\`bash
|
|
1463
|
+
# Synchronous execution
|
|
1464
|
+
curl -X POST https://example.com/api/${moduleName}/execute \\
|
|
1465
|
+
-H "Content-Type: application/json" \\
|
|
1466
|
+
-d '{"input": "Your input here"}'
|
|
1467
|
+
|
|
1468
|
+
# Asynchronous execution (queued)
|
|
1469
|
+
curl -X POST https://example.com/api/${moduleName}/execute-async \\
|
|
1470
|
+
-H "Content-Type: application/json" \\
|
|
1471
|
+
-d '{"input": "Your input here"}'
|
|
1472
|
+
\`\`\`
|
|
1473
|
+
|
|
1474
|
+
### Execute via PHP
|
|
1475
|
+
|
|
1476
|
+
\`\`\`php
|
|
1477
|
+
// Get service
|
|
1478
|
+
$agent = \\Drupal::service('${moduleName}.agent_executor');
|
|
1479
|
+
|
|
1480
|
+
// Execute synchronously
|
|
1481
|
+
$result = $agent->execute('Your input here');
|
|
1482
|
+
|
|
1483
|
+
if ($result['success']) {
|
|
1484
|
+
echo $result['output'];
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
// Execute asynchronously (queued)
|
|
1488
|
+
$queue_id = $agent->executeAsync('Your input here');
|
|
1489
|
+
\`\`\`
|
|
1490
|
+
|
|
1491
|
+
## Capabilities
|
|
1492
|
+
|
|
1493
|
+
${capabilities.map((c) => `- ${c}`).join('\n')}
|
|
1494
|
+
|
|
1495
|
+
## Tools
|
|
1496
|
+
|
|
1497
|
+
${tools.map((t) => `- **${t.name || 'unknown'}**: ${t.description || 'No description'}`).join('\n')}
|
|
1498
|
+
|
|
1499
|
+
${options.includeQueueWorker ? `
|
|
1500
|
+
## Queue Processing
|
|
1501
|
+
|
|
1502
|
+
The module includes a queue worker for asynchronous agent execution:
|
|
1503
|
+
|
|
1504
|
+
\`\`\`bash
|
|
1505
|
+
# Process queue via cron
|
|
1506
|
+
drush cron
|
|
1507
|
+
|
|
1508
|
+
# Process queue manually
|
|
1509
|
+
drush queue:run ${moduleName}_agent_queue
|
|
1510
|
+
\`\`\`
|
|
1511
|
+
` : ''}
|
|
1512
|
+
|
|
1513
|
+
${options.includeEntity ? `
|
|
1514
|
+
## Results Storage
|
|
1515
|
+
|
|
1516
|
+
All agent execution results are stored in the database and can be viewed at:
|
|
1517
|
+
\`/admin/${moduleName}/results\`
|
|
1518
|
+
|
|
1519
|
+
Results can also be queried via Views or entity queries:
|
|
1520
|
+
|
|
1521
|
+
\`\`\`php
|
|
1522
|
+
$storage = \\Drupal::entityTypeManager()->getStorage('${moduleName}_result');
|
|
1523
|
+
$results = $storage->loadMultiple();
|
|
1524
|
+
\`\`\`
|
|
1525
|
+
` : ''}
|
|
1526
|
+
|
|
1527
|
+
## Hooks
|
|
1528
|
+
|
|
1529
|
+
This module implements the following Drupal hooks:
|
|
1530
|
+
|
|
1531
|
+
${options.includeHooks ? `
|
|
1532
|
+
- \`hook_help()\`: Provides help text
|
|
1533
|
+
- \`hook_cron()\`: Processes queue items
|
|
1534
|
+
- \`hook_entity_presave()\`: Triggers agent on entity save (if enabled)
|
|
1535
|
+
- \`hook_theme()\`: Registers theme templates
|
|
1536
|
+
` : ''}
|
|
1537
|
+
|
|
1538
|
+
## Architecture
|
|
1539
|
+
|
|
1540
|
+
This module follows OSSA (Open Standard Agents) specification and uses:
|
|
1541
|
+
|
|
1542
|
+
- **ossa/symfony-bundle**: Core agent execution engine
|
|
1543
|
+
- **Dependency Injection**: Full Symfony DI container integration
|
|
1544
|
+
- **Queue System**: Drupal queue for async execution
|
|
1545
|
+
- **Entity API**: Drupal entities for result storage
|
|
1546
|
+
- **Configuration API**: Drupal configuration system
|
|
1547
|
+
|
|
1548
|
+
## Generated from OSSA
|
|
1549
|
+
|
|
1550
|
+
This module was generated from an OSSA v${manifest.apiVersion?.split('/')[1] || '{{VERSION}}'} manifest.
|
|
1551
|
+
|
|
1552
|
+
Original manifest: \`config/ossa/agent.ossa.yaml\`
|
|
1553
|
+
|
|
1554
|
+
## Support
|
|
1555
|
+
|
|
1556
|
+
- **OSSA Specification**: https://openstandardagents.org/
|
|
1557
|
+
- **Symfony Bundle**: https://github.com/blueflyio/openstandardagents
|
|
1558
|
+
- **Issue Tracker**: https://gitlab.com/blueflyio/ossa/openstandardagents/-/issues
|
|
1559
|
+
|
|
1560
|
+
## License
|
|
1561
|
+
|
|
1562
|
+
${manifest.metadata?.license || 'GPL-2.0-or-later'}
|
|
1563
|
+
`;
|
|
1564
|
+
}
|
|
1565
|
+
/**
|
|
1566
|
+
* Generate INSTALL.md
|
|
1567
|
+
*/
|
|
1568
|
+
generateInstallGuide(manifest, moduleName) {
|
|
1569
|
+
return `# Installation Guide: ${manifest.metadata?.name || moduleName}
|
|
1570
|
+
|
|
1571
|
+
## Prerequisites
|
|
1572
|
+
|
|
1573
|
+
- Drupal 10.x or 11.x
|
|
1574
|
+
- PHP 8.2 or higher
|
|
1575
|
+
- Composer
|
|
1576
|
+
- LLM provider API key (Anthropic, OpenAI, Google, or Azure)
|
|
1577
|
+
|
|
1578
|
+
## Step 1: Install Dependencies
|
|
1579
|
+
|
|
1580
|
+
\`\`\`bash
|
|
1581
|
+
cd /path/to/drupal
|
|
1582
|
+
composer require ossa/symfony-bundle
|
|
1583
|
+
\`\`\`
|
|
1584
|
+
|
|
1585
|
+
## Step 2: Install Module
|
|
1586
|
+
|
|
1587
|
+
### Option A: Via Composer (if published)
|
|
1588
|
+
|
|
1589
|
+
\`\`\`bash
|
|
1590
|
+
composer require drupal/${moduleName}
|
|
1591
|
+
drush en ${moduleName}
|
|
1592
|
+
\`\`\`
|
|
1593
|
+
|
|
1594
|
+
### Option B: Manual Installation
|
|
1595
|
+
|
|
1596
|
+
\`\`\`bash
|
|
1597
|
+
# Copy module directory
|
|
1598
|
+
cp -r ${moduleName} /path/to/drupal/web/modules/custom/
|
|
1599
|
+
|
|
1600
|
+
# Enable module
|
|
1601
|
+
drush en ${moduleName}
|
|
1602
|
+
|
|
1603
|
+
# Or via UI: Admin → Extend → Enable "${manifest.metadata?.name || moduleName}"
|
|
1604
|
+
\`\`\`
|
|
1605
|
+
|
|
1606
|
+
## Step 3: Configure API Keys
|
|
1607
|
+
|
|
1608
|
+
### Method 1: Environment Variables (Recommended)
|
|
1609
|
+
|
|
1610
|
+
Add to \`.env\` or export:
|
|
1611
|
+
|
|
1612
|
+
\`\`\`bash
|
|
1613
|
+
export ANTHROPIC_API_KEY="sk-ant-..."
|
|
1614
|
+
export OPENAI_API_KEY="sk-..."
|
|
1615
|
+
export GOOGLE_API_KEY="..."
|
|
1616
|
+
export AZURE_OPENAI_API_KEY="..."
|
|
1617
|
+
export AZURE_OPENAI_ENDPOINT="https://..."
|
|
1618
|
+
\`\`\`
|
|
1619
|
+
|
|
1620
|
+
### Method 2: settings.php
|
|
1621
|
+
|
|
1622
|
+
Add to \`sites/default/settings.php\`:
|
|
1623
|
+
|
|
1624
|
+
\`\`\`php
|
|
1625
|
+
// OSSA Provider Configuration
|
|
1626
|
+
$config['ossa']['providers']['anthropic']['api_key'] = getenv('ANTHROPIC_API_KEY');
|
|
1627
|
+
$config['ossa']['providers']['openai']['api_key'] = getenv('OPENAI_API_KEY');
|
|
1628
|
+
$config['ossa']['providers']['google']['api_key'] = getenv('GOOGLE_API_KEY');
|
|
1629
|
+
$config['ossa']['providers']['azure']['api_key'] = getenv('AZURE_OPENAI_API_KEY');
|
|
1630
|
+
$config['ossa']['providers']['azure']['base_url'] = getenv('AZURE_OPENAI_ENDPOINT');
|
|
1631
|
+
\`\`\`
|
|
1632
|
+
|
|
1633
|
+
## Step 4: Configure Module
|
|
1634
|
+
|
|
1635
|
+
1. Navigate to \`/admin/config/${moduleName}\`
|
|
1636
|
+
2. Select your preferred LLM provider
|
|
1637
|
+
3. Choose model (e.g., \`claude-sonnet-4-20250514\`)
|
|
1638
|
+
4. Adjust temperature (0.0-1.0)
|
|
1639
|
+
5. Configure auto-execution triggers (optional)
|
|
1640
|
+
6. Save configuration
|
|
1641
|
+
|
|
1642
|
+
## Step 5: Verify Installation
|
|
1643
|
+
|
|
1644
|
+
### Test via Drush
|
|
1645
|
+
|
|
1646
|
+
\`\`\`bash
|
|
1647
|
+
# List available agents
|
|
1648
|
+
drush ossa:agent:list
|
|
1649
|
+
|
|
1650
|
+
# Execute agent
|
|
1651
|
+
drush ossa:agent:execute ${manifest.metadata?.name || 'agent'} "Test input"
|
|
1652
|
+
\`\`\`
|
|
1653
|
+
|
|
1654
|
+
### Test via UI
|
|
1655
|
+
|
|
1656
|
+
1. Visit \`/admin/${moduleName}/execute\`
|
|
1657
|
+
2. Enter test input
|
|
1658
|
+
3. Click "Execute"
|
|
1659
|
+
4. Verify output appears
|
|
1660
|
+
|
|
1661
|
+
### Test via API
|
|
1662
|
+
|
|
1663
|
+
\`\`\`bash
|
|
1664
|
+
curl -X POST http://localhost/api/${moduleName}/execute \\
|
|
1665
|
+
-H "Content-Type: application/json" \\
|
|
1666
|
+
-d '{"input": "Hello, agent!"}'
|
|
1667
|
+
\`\`\`
|
|
1668
|
+
|
|
1669
|
+
## Step 6: Set Up Cron (Optional)
|
|
1670
|
+
|
|
1671
|
+
For asynchronous execution via queue:
|
|
1672
|
+
|
|
1673
|
+
\`\`\`bash
|
|
1674
|
+
# Configure Drupal cron
|
|
1675
|
+
drush cron
|
|
1676
|
+
|
|
1677
|
+
# Or set up system cron
|
|
1678
|
+
crontab -e
|
|
1679
|
+
# Add: */5 * * * * drush -r /path/to/drupal cron
|
|
1680
|
+
\`\`\`
|
|
1681
|
+
|
|
1682
|
+
## Troubleshooting
|
|
1683
|
+
|
|
1684
|
+
### Issue: "Missing API key"
|
|
1685
|
+
|
|
1686
|
+
**Solution**: Verify environment variables or settings.php configuration
|
|
1687
|
+
|
|
1688
|
+
\`\`\`bash
|
|
1689
|
+
# Check environment
|
|
1690
|
+
echo $ANTHROPIC_API_KEY
|
|
1691
|
+
|
|
1692
|
+
# Or verify in PHP
|
|
1693
|
+
drush php-eval "print_r(\\Drupal::config('ossa.settings')->get('providers'));"
|
|
1694
|
+
\`\`\`
|
|
1695
|
+
|
|
1696
|
+
### Issue: "Agent not found"
|
|
1697
|
+
|
|
1698
|
+
**Solution**: Clear cache
|
|
1699
|
+
|
|
1700
|
+
\`\`\`bash
|
|
1701
|
+
drush cr
|
|
1702
|
+
\`\`\`
|
|
1703
|
+
|
|
1704
|
+
### Issue: "Queue not processing"
|
|
1705
|
+
|
|
1706
|
+
**Solution**: Run cron manually
|
|
1707
|
+
|
|
1708
|
+
\`\`\`bash
|
|
1709
|
+
drush cron
|
|
1710
|
+
# Or process queue directly
|
|
1711
|
+
drush queue:run ${moduleName}_agent_queue
|
|
1712
|
+
\`\`\`
|
|
1713
|
+
|
|
1714
|
+
### Issue: "Permission denied"
|
|
1715
|
+
|
|
1716
|
+
**Solution**: Grant permissions
|
|
1717
|
+
|
|
1718
|
+
1. Visit \`/admin/people/permissions\`
|
|
1719
|
+
2. Grant "Administer ${moduleName}" permission
|
|
1720
|
+
3. Save permissions
|
|
1721
|
+
|
|
1722
|
+
## Next Steps
|
|
1723
|
+
|
|
1724
|
+
- Configure auto-execution triggers
|
|
1725
|
+
- Set up Views for result browsing
|
|
1726
|
+
- Integrate with custom modules
|
|
1727
|
+
- Monitor execution logs
|
|
1728
|
+
|
|
1729
|
+
## Support
|
|
1730
|
+
|
|
1731
|
+
- Documentation: https://openstandardagents.org/
|
|
1732
|
+
- Issues: https://gitlab.com/blueflyio/ossa/openstandardagents/-/issues
|
|
1733
|
+
- Drupal.org: https://www.drupal.org/project/${moduleName}
|
|
1734
|
+
`;
|
|
1735
|
+
}
|
|
1736
|
+
// ===================================================================
|
|
1737
|
+
// Utility Methods
|
|
1738
|
+
// ===================================================================
|
|
1739
|
+
/**
|
|
1740
|
+
* Sanitize module name for Drupal
|
|
1741
|
+
*/
|
|
1742
|
+
sanitizeModuleName(name) {
|
|
1743
|
+
return name
|
|
1744
|
+
.toLowerCase()
|
|
1745
|
+
.replace(/[^a-z0-9_]/g, '_')
|
|
1746
|
+
.replace(/^[0-9]+/, '')
|
|
1747
|
+
.replace(/_+/g, '_')
|
|
1748
|
+
.replace(/^_|_$/g, '');
|
|
1749
|
+
}
|
|
1750
|
+
/**
|
|
1751
|
+
* Convert module name to class name (PascalCase)
|
|
1752
|
+
*/
|
|
1753
|
+
toClassName(moduleName) {
|
|
1754
|
+
return moduleName
|
|
1755
|
+
.split('_')
|
|
1756
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
1757
|
+
.join('');
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
//# sourceMappingURL=generator.js.map
|