@bluefly/openstandardagents 0.4.0 → 0.4.2

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.
Files changed (517) hide show
  1. package/CHANGELOG.md +137 -0
  2. package/DEMO.md +212 -0
  3. package/README.md +77 -17
  4. package/dist/adapters/drupal/generator.d.ts +149 -0
  5. package/dist/adapters/drupal/generator.d.ts.map +1 -0
  6. package/dist/adapters/drupal/generator.js +1760 -0
  7. package/dist/adapters/drupal/generator.js.map +1 -0
  8. package/dist/adapters/drupal/index.d.ts +2 -0
  9. package/dist/adapters/drupal/index.d.ts.map +1 -1
  10. package/dist/adapters/drupal/index.js +3 -0
  11. package/dist/adapters/drupal/index.js.map +1 -1
  12. package/dist/adapters/npm/adapter.js +2 -2
  13. package/dist/adapters/npm/converter.js +3 -3
  14. package/dist/cli/banner.d.ts +21 -0
  15. package/dist/cli/banner.d.ts.map +1 -0
  16. package/dist/cli/banner.js +128 -0
  17. package/dist/cli/banner.js.map +1 -0
  18. package/dist/cli/commands/dev.command.d.ts +20 -0
  19. package/dist/cli/commands/dev.command.d.ts.map +1 -0
  20. package/dist/cli/commands/dev.command.js +78 -0
  21. package/dist/cli/commands/dev.command.js.map +1 -0
  22. package/dist/cli/commands/estimate.command.d.ts +12 -0
  23. package/dist/cli/commands/estimate.command.d.ts.map +1 -0
  24. package/dist/cli/commands/estimate.command.js +226 -0
  25. package/dist/cli/commands/estimate.command.js.map +1 -0
  26. package/dist/cli/commands/export-enhanced.command.d.ts +7 -0
  27. package/dist/cli/commands/export-enhanced.command.d.ts.map +1 -0
  28. package/dist/cli/commands/{export-v2.command.js → export-enhanced.command.js} +3 -3
  29. package/dist/cli/commands/export-enhanced.command.js.map +1 -0
  30. package/dist/cli/commands/export.command.d.ts.map +1 -1
  31. package/dist/cli/commands/export.command.js +82 -4
  32. package/dist/cli/commands/export.command.js.map +1 -1
  33. package/dist/cli/commands/init.command.d.ts.map +1 -1
  34. package/dist/cli/commands/init.command.js +2 -0
  35. package/dist/cli/commands/init.command.js.map +1 -1
  36. package/dist/cli/commands/test.command.d.ts +1 -0
  37. package/dist/cli/commands/test.command.d.ts.map +1 -1
  38. package/dist/cli/commands/test.command.js +172 -105
  39. package/dist/cli/commands/test.command.js.map +1 -1
  40. package/dist/cli/commands/types/wizard-config.types.d.ts +59 -0
  41. package/dist/cli/commands/types/wizard-config.types.d.ts.map +1 -0
  42. package/dist/cli/commands/types/wizard-config.types.js +34 -0
  43. package/dist/cli/commands/types/wizard-config.types.js.map +1 -0
  44. package/dist/cli/commands/upgrade.command.d.ts +9 -0
  45. package/dist/cli/commands/upgrade.command.d.ts.map +1 -0
  46. package/dist/cli/commands/upgrade.command.js +167 -0
  47. package/dist/cli/commands/upgrade.command.js.map +1 -0
  48. package/dist/cli/commands/wizard-api-first.command.d.ts +18 -0
  49. package/dist/cli/commands/wizard-api-first.command.d.ts.map +1 -0
  50. package/dist/cli/commands/wizard-api-first.command.js +854 -0
  51. package/dist/cli/commands/wizard-api-first.command.js.map +1 -0
  52. package/dist/cli/commands/wizard-interactive.command.d.ts +25 -0
  53. package/dist/cli/commands/wizard-interactive.command.d.ts.map +1 -0
  54. package/dist/cli/commands/wizard-interactive.command.js +1875 -0
  55. package/dist/cli/commands/wizard-interactive.command.js.map +1 -0
  56. package/dist/cli/commands/workspace.command.js +1 -1
  57. package/dist/cli/commands/workspace.command.js.map +1 -1
  58. package/dist/cli/index.js +9 -0
  59. package/dist/cli/index.js.map +1 -1
  60. package/dist/cli/schema-driven/index.d.ts +27 -0
  61. package/dist/cli/schema-driven/index.d.ts.map +1 -0
  62. package/dist/cli/schema-driven/index.js +34 -0
  63. package/dist/cli/schema-driven/index.js.map +1 -0
  64. package/dist/cli/schema-driven/schema-loader.d.ts +115 -0
  65. package/dist/cli/schema-driven/schema-loader.d.ts.map +1 -0
  66. package/dist/cli/schema-driven/schema-loader.js +270 -0
  67. package/dist/cli/schema-driven/schema-loader.js.map +1 -0
  68. package/dist/cli/schema-driven/ui-generator.d.ts +88 -0
  69. package/dist/cli/schema-driven/ui-generator.d.ts.map +1 -0
  70. package/dist/cli/schema-driven/ui-generator.js +326 -0
  71. package/dist/cli/schema-driven/ui-generator.js.map +1 -0
  72. package/dist/cli/wizard/interactive-wizard.d.ts +26 -0
  73. package/dist/cli/wizard/interactive-wizard.d.ts.map +1 -0
  74. package/dist/cli/wizard/interactive-wizard.js +296 -0
  75. package/dist/cli/wizard/interactive-wizard.js.map +1 -0
  76. package/dist/cli/wizard/template-catalog.d.ts +32 -0
  77. package/dist/cli/wizard/template-catalog.d.ts.map +1 -0
  78. package/dist/cli/wizard/template-catalog.js +99 -0
  79. package/dist/cli/wizard/template-catalog.js.map +1 -0
  80. package/dist/cli/wizard/use-cases.d.ts +37 -0
  81. package/dist/cli/wizard/use-cases.d.ts.map +1 -0
  82. package/dist/cli/wizard/use-cases.js +157 -0
  83. package/dist/cli/wizard/use-cases.js.map +1 -0
  84. package/dist/di-container.d.ts.map +1 -1
  85. package/dist/di-container.js +2 -0
  86. package/dist/di-container.js.map +1 -1
  87. package/dist/package.json +33 -11
  88. package/dist/runtime/agent-runner.d.ts +46 -0
  89. package/dist/runtime/agent-runner.d.ts.map +1 -0
  90. package/dist/runtime/agent-runner.js +346 -0
  91. package/dist/runtime/agent-runner.js.map +1 -0
  92. package/dist/sdks/kagent/crd-generator.d.ts +4 -0
  93. package/dist/sdks/kagent/crd-generator.d.ts.map +1 -1
  94. package/dist/sdks/kagent/crd-generator.js +83 -2
  95. package/dist/sdks/kagent/crd-generator.js.map +1 -1
  96. package/dist/sdks/kagent/k8s-resources-generator.d.ts +73 -0
  97. package/dist/sdks/kagent/k8s-resources-generator.d.ts.map +1 -0
  98. package/dist/sdks/kagent/k8s-resources-generator.js +286 -0
  99. package/dist/sdks/kagent/k8s-resources-generator.js.map +1 -0
  100. package/dist/sdks/kagent/types.d.ts +79 -0
  101. package/dist/sdks/kagent/types.d.ts.map +1 -1
  102. package/dist/sdks/shared/validation.d.ts +2 -2
  103. package/dist/services/cost-estimation/optimization-patterns.d.ts +23 -0
  104. package/dist/services/cost-estimation/optimization-patterns.d.ts.map +1 -0
  105. package/dist/services/cost-estimation/optimization-patterns.js +147 -0
  106. package/dist/services/cost-estimation/optimization-patterns.js.map +1 -0
  107. package/dist/services/cost-estimation/pricing.d.ts +29 -0
  108. package/dist/services/cost-estimation/pricing.d.ts.map +1 -0
  109. package/dist/services/cost-estimation/pricing.js +225 -0
  110. package/dist/services/cost-estimation/pricing.js.map +1 -0
  111. package/dist/services/cost-estimation/scenario-estimator.d.ts +59 -0
  112. package/dist/services/cost-estimation/scenario-estimator.d.ts.map +1 -0
  113. package/dist/services/cost-estimation/scenario-estimator.js +145 -0
  114. package/dist/services/cost-estimation/scenario-estimator.js.map +1 -0
  115. package/dist/services/cost-estimation/token-counter.service.d.ts +51 -0
  116. package/dist/services/cost-estimation/token-counter.service.d.ts.map +1 -0
  117. package/dist/services/cost-estimation/token-counter.service.js +125 -0
  118. package/dist/services/cost-estimation/token-counter.service.js.map +1 -0
  119. package/dist/services/dev-server/dev-server.service.d.ts +121 -0
  120. package/dist/services/dev-server/dev-server.service.d.ts.map +1 -0
  121. package/dist/services/dev-server/dev-server.service.js +290 -0
  122. package/dist/services/dev-server/dev-server.service.js.map +1 -0
  123. package/dist/services/dev-server/file-watcher.d.ts +101 -0
  124. package/dist/services/dev-server/file-watcher.d.ts.map +1 -0
  125. package/dist/services/dev-server/file-watcher.js +190 -0
  126. package/dist/services/dev-server/file-watcher.js.map +1 -0
  127. package/dist/services/dev-server/live-validator.d.ts +157 -0
  128. package/dist/services/dev-server/live-validator.d.ts.map +1 -0
  129. package/dist/services/dev-server/live-validator.js +301 -0
  130. package/dist/services/dev-server/live-validator.js.map +1 -0
  131. package/dist/services/dev-server/websocket-server.d.ts +137 -0
  132. package/dist/services/dev-server/websocket-server.d.ts.map +1 -0
  133. package/dist/services/dev-server/websocket-server.js +229 -0
  134. package/dist/services/dev-server/websocket-server.js.map +1 -0
  135. package/dist/services/export/anthropic/anthropic-exporter.d.ts +70 -0
  136. package/dist/services/export/anthropic/anthropic-exporter.d.ts.map +1 -0
  137. package/dist/services/export/anthropic/anthropic-exporter.js +576 -0
  138. package/dist/services/export/anthropic/anthropic-exporter.js.map +1 -0
  139. package/dist/services/export/anthropic/api-generator.d.ts +39 -0
  140. package/dist/services/export/anthropic/api-generator.d.ts.map +1 -0
  141. package/dist/services/export/anthropic/api-generator.js +395 -0
  142. package/dist/services/export/anthropic/api-generator.js.map +1 -0
  143. package/dist/services/export/anthropic/index.d.ts +18 -0
  144. package/dist/services/export/anthropic/index.d.ts.map +1 -0
  145. package/dist/services/export/anthropic/index.js +16 -0
  146. package/dist/services/export/anthropic/index.js.map +1 -0
  147. package/dist/services/export/anthropic/tools-generator.d.ts +35 -0
  148. package/dist/services/export/anthropic/tools-generator.d.ts.map +1 -0
  149. package/dist/services/export/anthropic/tools-generator.js +260 -0
  150. package/dist/services/export/anthropic/tools-generator.js.map +1 -0
  151. package/dist/services/export/langchain/api-generator.d.ts +17 -0
  152. package/dist/services/export/langchain/api-generator.d.ts.map +1 -0
  153. package/dist/services/export/langchain/api-generator.js +375 -0
  154. package/dist/services/export/langchain/api-generator.js.map +1 -0
  155. package/dist/services/export/langchain/callbacks-generator.d.ts +63 -0
  156. package/dist/services/export/langchain/callbacks-generator.d.ts.map +1 -0
  157. package/dist/services/export/langchain/callbacks-generator.js +408 -0
  158. package/dist/services/export/langchain/callbacks-generator.js.map +1 -0
  159. package/dist/services/export/langchain/error-handling-generator.d.ts +76 -0
  160. package/dist/services/export/langchain/error-handling-generator.d.ts.map +1 -0
  161. package/dist/services/export/langchain/error-handling-generator.js +522 -0
  162. package/dist/services/export/langchain/error-handling-generator.js.map +1 -0
  163. package/dist/services/export/langchain/index.d.ts +17 -0
  164. package/dist/services/export/langchain/index.d.ts.map +1 -0
  165. package/dist/services/export/langchain/index.js +13 -0
  166. package/dist/services/export/langchain/index.js.map +1 -0
  167. package/dist/services/export/langchain/langchain-exporter.d.ts +174 -0
  168. package/dist/services/export/langchain/langchain-exporter.d.ts.map +1 -0
  169. package/dist/services/export/langchain/langchain-exporter.js +953 -0
  170. package/dist/services/export/langchain/langchain-exporter.js.map +1 -0
  171. package/dist/services/export/langchain/langgraph-generator.d.ts +86 -0
  172. package/dist/services/export/langchain/langgraph-generator.d.ts.map +1 -0
  173. package/dist/services/export/langchain/langgraph-generator.js +473 -0
  174. package/dist/services/export/langchain/langgraph-generator.js.map +1 -0
  175. package/dist/services/export/langchain/langserve-generator.d.ts +95 -0
  176. package/dist/services/export/langchain/langserve-generator.d.ts.map +1 -0
  177. package/dist/services/export/langchain/langserve-generator.js +807 -0
  178. package/dist/services/export/langchain/langserve-generator.js.map +1 -0
  179. package/dist/services/export/langchain/memory-generator.d.ts +71 -0
  180. package/dist/services/export/langchain/memory-generator.d.ts.map +1 -0
  181. package/dist/services/export/langchain/memory-generator.js +1182 -0
  182. package/dist/services/export/langchain/memory-generator.js.map +1 -0
  183. package/dist/services/export/langchain/openapi-generator.d.ts +20 -0
  184. package/dist/services/export/langchain/openapi-generator.d.ts.map +1 -0
  185. package/dist/services/export/langchain/openapi-generator.js +364 -0
  186. package/dist/services/export/langchain/openapi-generator.js.map +1 -0
  187. package/dist/services/export/langchain/plan-execute-generator.d.ts +60 -0
  188. package/dist/services/export/langchain/plan-execute-generator.d.ts.map +1 -0
  189. package/dist/services/export/langchain/plan-execute-generator.js +679 -0
  190. package/dist/services/export/langchain/plan-execute-generator.js.map +1 -0
  191. package/dist/services/export/langchain/streaming-generator.d.ts +66 -0
  192. package/dist/services/export/langchain/streaming-generator.d.ts.map +1 -0
  193. package/dist/services/export/langchain/streaming-generator.js +749 -0
  194. package/dist/services/export/langchain/streaming-generator.js.map +1 -0
  195. package/dist/services/export/langchain/tools-generator.d.ts +67 -0
  196. package/dist/services/export/langchain/tools-generator.d.ts.map +1 -0
  197. package/dist/services/export/langchain/tools-generator.js +543 -0
  198. package/dist/services/export/langchain/tools-generator.js.map +1 -0
  199. package/dist/services/export/npm/express-generator.d.ts +23 -0
  200. package/dist/services/export/npm/express-generator.d.ts.map +1 -0
  201. package/dist/services/export/npm/express-generator.js +296 -0
  202. package/dist/services/export/npm/express-generator.js.map +1 -0
  203. package/dist/services/export/npm/index.d.ts +13 -0
  204. package/dist/services/export/npm/index.d.ts.map +1 -0
  205. package/dist/services/export/npm/index.js +11 -0
  206. package/dist/services/export/npm/index.js.map +1 -0
  207. package/dist/services/export/npm/npm-exporter.d.ts +142 -0
  208. package/dist/services/export/npm/npm-exporter.d.ts.map +1 -0
  209. package/dist/services/export/npm/npm-exporter.js +480 -0
  210. package/dist/services/export/npm/npm-exporter.js.map +1 -0
  211. package/dist/services/export/npm/openapi-generator.d.ts +19 -0
  212. package/dist/services/export/npm/openapi-generator.d.ts.map +1 -0
  213. package/dist/services/export/npm/openapi-generator.js +428 -0
  214. package/dist/services/export/npm/openapi-generator.js.map +1 -0
  215. package/dist/services/export/npm/package-json-generator.d.ts +31 -0
  216. package/dist/services/export/npm/package-json-generator.d.ts.map +1 -0
  217. package/dist/services/export/npm/package-json-generator.js +153 -0
  218. package/dist/services/export/npm/package-json-generator.js.map +1 -0
  219. package/dist/services/export/npm/typescript-generator.d.ts +69 -0
  220. package/dist/services/export/npm/typescript-generator.d.ts.map +1 -0
  221. package/dist/services/export/npm/typescript-generator.js +437 -0
  222. package/dist/services/export/npm/typescript-generator.js.map +1 -0
  223. package/dist/services/export/testing/index.d.ts +8 -0
  224. package/dist/services/export/testing/index.d.ts.map +1 -0
  225. package/dist/services/export/testing/index.js +7 -0
  226. package/dist/services/export/testing/index.js.map +1 -0
  227. package/dist/services/export/testing/test-generator.d.ts +178 -0
  228. package/dist/services/export/testing/test-generator.d.ts.map +1 -0
  229. package/dist/services/export/testing/test-generator.js +2542 -0
  230. package/dist/services/export/testing/test-generator.js.map +1 -0
  231. package/dist/services/test-runner/mock-llm.service.d.ts +77 -0
  232. package/dist/services/test-runner/mock-llm.service.d.ts.map +1 -0
  233. package/dist/services/test-runner/mock-llm.service.js +173 -0
  234. package/dist/services/test-runner/mock-llm.service.js.map +1 -0
  235. package/dist/services/test-runner/scenarios.d.ts +36 -0
  236. package/dist/services/test-runner/scenarios.d.ts.map +1 -0
  237. package/dist/services/test-runner/scenarios.js +196 -0
  238. package/dist/services/test-runner/scenarios.js.map +1 -0
  239. package/dist/services/test-runner/test-runner.service.d.ts +19 -1
  240. package/dist/services/test-runner/test-runner.service.d.ts.map +1 -1
  241. package/dist/services/test-runner/test-runner.service.js +72 -6
  242. package/dist/services/test-runner/test-runner.service.js.map +1 -1
  243. package/dist/services/validation/best-practices-validator.d.ts +84 -0
  244. package/dist/services/validation/best-practices-validator.d.ts.map +1 -0
  245. package/dist/services/validation/best-practices-validator.js +499 -0
  246. package/dist/services/validation/best-practices-validator.js.map +1 -0
  247. package/dist/services/validation/cost-estimator.d.ts +69 -0
  248. package/dist/services/validation/cost-estimator.d.ts.map +1 -0
  249. package/dist/services/validation/cost-estimator.js +221 -0
  250. package/dist/services/validation/cost-estimator.js.map +1 -0
  251. package/dist/services/validation/enhanced-validator.d.ts +78 -0
  252. package/dist/services/validation/enhanced-validator.d.ts.map +1 -0
  253. package/dist/services/validation/enhanced-validator.js +212 -0
  254. package/dist/services/validation/enhanced-validator.js.map +1 -0
  255. package/dist/services/validation/index.d.ts +13 -0
  256. package/dist/services/validation/index.d.ts.map +1 -0
  257. package/dist/services/validation/index.js +9 -0
  258. package/dist/services/validation/index.js.map +1 -0
  259. package/dist/services/validation/security-validator.d.ts +81 -0
  260. package/dist/services/validation/security-validator.d.ts.map +1 -0
  261. package/dist/services/validation/security-validator.js +328 -0
  262. package/dist/services/validation/security-validator.js.map +1 -0
  263. package/dist/services/wizard/prompts.d.ts +71 -0
  264. package/dist/services/wizard/prompts.d.ts.map +1 -0
  265. package/dist/services/wizard/prompts.js +322 -0
  266. package/dist/services/wizard/prompts.js.map +1 -0
  267. package/dist/services/wizard/wizard.service.d.ts +60 -0
  268. package/dist/services/wizard/wizard.service.d.ts.map +1 -0
  269. package/dist/services/wizard/wizard.service.js +261 -0
  270. package/dist/services/wizard/wizard.service.js.map +1 -0
  271. package/dist/types/personality.zod.d.ts +23 -23
  272. package/dist/utils/version.d.ts +1 -1
  273. package/dist/utils/version.js +1 -1
  274. package/dist/version-management/core/version-manager.test.js.map +1 -1
  275. package/dist/version.d.ts +62 -0
  276. package/dist/version.d.ts.map +1 -0
  277. package/dist/version.js +73 -0
  278. package/dist/version.js.map +1 -0
  279. package/examples/a2a/agent-handoff.ossa.yaml +1 -1
  280. package/examples/a2a/service-discovery.ossa.yaml +1 -1
  281. package/examples/adapters/drupal-eca-mapping.yaml +1 -1
  282. package/examples/adapters/drupal-eca-task.yaml +1 -1
  283. package/examples/adapters/drupal-flowdrop-mapping.yaml +1 -1
  284. package/examples/adapters/drupal-maestro-mapping.yaml +1 -1
  285. package/examples/adapters/mistral-agent.yaml +1 -1
  286. package/examples/adapters/symfony-messenger-task.yaml +1 -1
  287. package/examples/adapters/symfony-messenger-workflow.yaml +1 -1
  288. package/examples/adk-integration/code-review-workflow.yml +1 -1
  289. package/examples/adk-integration/customer-support.yml +1 -1
  290. package/examples/adk-integration/data-pipeline.yml +1 -1
  291. package/examples/advanced/reasoning-agent.yaml +1 -1
  292. package/examples/advanced/workflows/hybrid-model-strategy.yaml +1 -1
  293. package/examples/agent-manifests/critics/critic-agent.yaml +1 -1
  294. package/examples/agent-manifests/governors/governor-agent.yaml +1 -1
  295. package/examples/agent-manifests/integrators/integrator-agent.yaml +1 -1
  296. package/examples/agent-manifests/judges/judge-agent.yaml +1 -1
  297. package/examples/agent-manifests/monitors/monitor-agent.yaml +1 -1
  298. package/examples/agent-manifests/orchestrators/orchestrator-agent.yaml +1 -1
  299. package/examples/agent-manifests/sample-compliant-agent.yaml +1 -1
  300. package/examples/agent-manifests/workers/worker-agent.yaml +1 -1
  301. package/examples/agents/01-customer-support-bot/.env.example +32 -0
  302. package/examples/agents/01-customer-support-bot/Dockerfile +30 -0
  303. package/examples/agents/01-customer-support-bot/README.md +295 -0
  304. package/examples/agents/01-customer-support-bot/agent.ossa.yaml +172 -0
  305. package/examples/agents/01-customer-support-bot/docker-compose.yml +55 -0
  306. package/examples/agents/01-customer-support-bot/openapi.yaml +238 -0
  307. package/examples/agents/01-customer-support-bot/package.json +48 -0
  308. package/examples/agents/02-code-review-agent/README.md +72 -0
  309. package/examples/agents/02-code-review-agent/agent.ossa.yaml +239 -0
  310. package/examples/agents/02-code-review-agent/docker-compose.yml +22 -0
  311. package/examples/agents/02-code-review-agent/openapi.yaml +150 -0
  312. package/examples/agents/03-data-analysis-agent/README.md +51 -0
  313. package/examples/agents/03-data-analysis-agent/agent.ossa.yaml +97 -0
  314. package/examples/agents/03-data-analysis-agent/openapi.yaml +74 -0
  315. package/examples/agents/04-content-moderator/README.md +55 -0
  316. package/examples/agents/04-content-moderator/agent.ossa.yaml +131 -0
  317. package/examples/agents/04-content-moderator/openapi.yaml +50 -0
  318. package/examples/agents/05-sales-assistant/README.md +37 -0
  319. package/examples/agents/05-sales-assistant/agent.ossa.yaml +146 -0
  320. package/examples/agents/05-sales-assistant/openapi.yaml +59 -0
  321. package/examples/agents/06-devops-agent/README.md +39 -0
  322. package/examples/agents/06-devops-agent/agent.ossa.yaml +141 -0
  323. package/examples/agents/06-devops-agent/openapi.yaml +51 -0
  324. package/examples/agents/07-research-assistant/README.md +31 -0
  325. package/examples/agents/07-research-assistant/agent.ossa.yaml +119 -0
  326. package/examples/agents/07-research-assistant/openapi.yaml +56 -0
  327. package/examples/agents/08-email-triage-agent/README.md +33 -0
  328. package/examples/agents/08-email-triage-agent/agent.ossa.yaml +133 -0
  329. package/examples/agents/08-email-triage-agent/openapi.yaml +41 -0
  330. package/examples/agents/09-security-scanner/README.md +49 -0
  331. package/examples/agents/09-security-scanner/agent.ossa.yaml +174 -0
  332. package/examples/agents/09-security-scanner/openapi.yaml +46 -0
  333. package/examples/agents/10-meeting-assistant/README.md +53 -0
  334. package/examples/agents/10-meeting-assistant/agent.ossa.yaml +211 -0
  335. package/examples/agents/10-meeting-assistant/docker-compose.yml +27 -0
  336. package/examples/agents/10-meeting-assistant/openapi.yaml +131 -0
  337. package/examples/agents/COMPLETION_REPORT.txt +272 -0
  338. package/examples/agents/INDEX.md +296 -0
  339. package/examples/agents/README.md +452 -0
  340. package/examples/agents/SUMMARY.md +362 -0
  341. package/examples/agents/TEST_RESULTS.md +458 -0
  342. package/examples/agents/architecture-healer-enterprise.yaml +1 -1
  343. package/examples/agents/dependency-healer-npm.yaml +1 -1
  344. package/examples/agents/spec-healer-openapi.yaml +1 -1
  345. package/examples/agents/wiki-healer-production.yaml +1 -1
  346. package/examples/agents-md/code-agent.ossa.json +1 -1
  347. package/examples/agents-md/monorepo-agent.ossa.yaml +1 -1
  348. package/examples/anthropic/claude-assistant.ossa.json +1 -1
  349. package/examples/autogen/multi-agent.ossa.json +1 -1
  350. package/examples/autonomous-evolution/self-evolving-agent.ossa.yaml +1 -1
  351. package/examples/build-once-use-everywhere/agent.ossa.yaml +1 -1
  352. package/examples/claude-code/code-reviewer.ossa.yaml +1 -1
  353. package/examples/claude-code/ossa-validator.ossa.yaml +1 -1
  354. package/examples/common_npm/agent-router.ossa.yaml +2 -2
  355. package/examples/contracts/data-consumer.ossa.yaml +1 -1
  356. package/examples/contracts/data-producer-v2.ossa.yaml +1 -1
  357. package/examples/contracts/data-producer.ossa.yaml +1 -1
  358. package/examples/crewai/research-team.ossa.json +1 -1
  359. package/examples/cursor/code-review-agent.ossa.json +1 -1
  360. package/examples/drupal/QUICKSTART.md +439 -0
  361. package/examples/drupal/ai_agents_ossa-module/.agents/example-agent/agent.ossa.yaml +1 -1
  362. package/examples/drupal/content-moderator.ossa.yaml +107 -0
  363. package/examples/drupal/gitlab-ml-recommender.ossa.yaml +2 -2
  364. package/examples/economics/marketplace-agent.ossa.json +1 -1
  365. package/examples/export/langchain/production-agent-with-memory/README.md +373 -0
  366. package/examples/export/langchain/production-agent-with-memory/agent.ossa.yaml +97 -0
  367. package/examples/export/langchain/production-agent-with-streaming/README.md +617 -0
  368. package/examples/export/langchain/production-agent-with-streaming/agent.ossa.yaml +100 -0
  369. package/examples/export/langchain/production-agent-with-streaming/client-example.py +263 -0
  370. package/examples/export/langchain/production-agent-with-tools/README.md +296 -0
  371. package/examples/export/langchain/production-agent-with-tools/agent.ossa.yaml +216 -0
  372. package/examples/export/langchain-export-example.ts +246 -0
  373. package/examples/export/langserve-export-example.ts +246 -0
  374. package/examples/export/test-generation-example.ts +457 -0
  375. package/examples/extensions/agents-md-advanced.yml +1 -1
  376. package/examples/extensions/agents-md-basic.yml +1 -1
  377. package/examples/extensions/agents-md-sync.yml +1 -1
  378. package/examples/extensions/agents-md-v1.yml +1 -1
  379. package/examples/extensions/drupal-v1.yml +1 -1
  380. package/examples/extensions/encryption-multi-provider.yaml +4 -4
  381. package/examples/extensions/kagent-v1.yml +1 -1
  382. package/examples/extensions/knowledge-sources.yaml +1 -1
  383. package/examples/extensions/mcp-full-featured.yaml +1 -1
  384. package/examples/genetics/breeding-agent.ossa.json +1 -1
  385. package/examples/getting-started/01-minimal-agent.ossa.yaml +1 -1
  386. package/examples/getting-started/02-agent-with-tools.ossa.yaml +1 -1
  387. package/examples/getting-started/03-agent-with-safety.ossa.yaml +1 -1
  388. package/examples/getting-started/04-agent-with-messaging.ossa.yaml +1 -1
  389. package/examples/getting-started/05-workflow-composition.ossa.yaml +1 -1
  390. package/examples/getting-started/hello-world-complete.ossa.yaml +1 -1
  391. package/examples/integration-patterns/agent-to-agent-orchestration.ossa.yaml +1 -1
  392. package/examples/kagent/compliance-validator.ossa.yaml +1 -1
  393. package/examples/kagent/cost-optimizer.ossa.yaml +1 -1
  394. package/examples/kagent/documentation-agent.ossa.yaml +1 -1
  395. package/examples/kagent/k8s-troubleshooter-v1.ossa.yaml +2 -2
  396. package/examples/kagent/k8s-troubleshooter.ossa.yaml +1 -1
  397. package/examples/kagent/security-scanner.ossa.yaml +1 -1
  398. package/examples/langchain/chain-agent.ossa.json +1 -1
  399. package/examples/langflow/workflow-agent.ossa.json +1 -1
  400. package/examples/langgraph/state-machine-agent.ossa.json +1 -1
  401. package/examples/lifecycle/mentoring-agent.ossa.json +1 -1
  402. package/examples/llamaindex/rag-agent.ossa.json +1 -1
  403. package/examples/mcp/database-mcp.ossa.yaml +1 -1
  404. package/examples/mcp/filesystem-mcp.ossa.yaml +1 -1
  405. package/examples/messaging/dependency-healer.ossa.yaml +1 -1
  406. package/examples/messaging/incident-responder.ossa.yaml +1 -1
  407. package/examples/messaging/routing-rules.ossa.yaml +1 -1
  408. package/examples/messaging/security-scanner.ossa.yaml +1 -1
  409. package/examples/migration-guides/from-langchain-to-ossa.yaml +4 -4
  410. package/examples/migrations/langchain/01-python-react-agent-after.ossa.yaml +1 -1
  411. package/examples/migrations/langchain/02-typescript-conversational-after.ossa.yaml +1 -1
  412. package/examples/migrations/langchain/03-sequential-chain-after.ossa.yaml +1 -1
  413. package/examples/migrations/langchain/04-config-based-after.ossa.yaml +1 -1
  414. package/examples/migrations/swarm-to-ossa/after-handoffs.ossa.yaml +6 -6
  415. package/examples/migrations/swarm-to-ossa/after-triage-agent.ossa.yaml +3 -3
  416. package/examples/multi-agent/conditional-router.ossa.yaml +1 -1
  417. package/examples/multi-agent/parallel-execution.ossa.yaml +1 -1
  418. package/examples/multi-agent/sequential-pipeline.ossa.yaml +1 -1
  419. package/examples/multi-agent-research-workflow.ossa.yaml +133 -0
  420. package/examples/multi-platform/single-manifest/agent.ossa.yaml +1 -1
  421. package/examples/npm-export-example.ts +150 -0
  422. package/examples/observability/activity-stream-full.yaml +1 -1
  423. package/examples/openai/basic-agent.ossa.yaml +1 -1
  424. package/examples/openai/multi-tool-agent.ossa.json +1 -1
  425. package/examples/openai/swarm-agent.ossa.json +1 -1
  426. package/examples/ossa-templates/01-code-assistant.ossa.yaml +1 -1
  427. package/examples/ossa-templates/02-security-scanner.ossa.yaml +1 -1
  428. package/examples/ossa-templates/03-ci-pipeline.ossa.yaml +1 -1
  429. package/examples/ossa-templates/04-code-reviewer.ossa.yaml +1 -1
  430. package/examples/ossa-templates/05-doc-generator.ossa.yaml +1 -1
  431. package/examples/ossa-templates/06-compliance-validator.ossa.yaml +1 -1
  432. package/examples/ossa-templates/07-workflow-orchestrator.ossa.yaml +1 -1
  433. package/examples/ossa-templates/08-content-writer.ossa.yaml +1 -1
  434. package/examples/ossa-templates/09-test-generator.ossa.yaml +1 -1
  435. package/examples/ossa-templates/10-data-transformer.ossa.yaml +1 -1
  436. package/examples/ossa-templates/11-react-performance-expert.ossa.yaml +1 -1
  437. package/examples/ossa-templates/12-typescript-type-safety-expert.ossa.yaml +1 -1
  438. package/examples/ossa-templates/13-accessibility-champion.ossa.yaml +1 -1
  439. package/examples/ossa-templates/14-security-hardening-agent.ossa.yaml +1 -1
  440. package/examples/production/document-analyzer-openai.yml +1 -1
  441. package/examples/production-ready/01-customer-support-bot/.env.example +32 -0
  442. package/examples/production-ready/01-customer-support-bot/Dockerfile +30 -0
  443. package/examples/production-ready/01-customer-support-bot/README.md +295 -0
  444. package/examples/production-ready/01-customer-support-bot/agent.ossa.yaml +172 -0
  445. package/examples/production-ready/01-customer-support-bot/docker-compose.yml +55 -0
  446. package/examples/production-ready/01-customer-support-bot/openapi.yaml +238 -0
  447. package/examples/production-ready/01-customer-support-bot/package.json +48 -0
  448. package/examples/production-ready/02-code-review-agent/README.md +72 -0
  449. package/examples/production-ready/02-code-review-agent/agent.ossa.yaml +239 -0
  450. package/examples/production-ready/02-code-review-agent/docker-compose.yml +22 -0
  451. package/examples/production-ready/02-code-review-agent/openapi.yaml +150 -0
  452. package/examples/production-ready/03-data-analysis-agent/README.md +51 -0
  453. package/examples/production-ready/03-data-analysis-agent/agent.ossa.yaml +97 -0
  454. package/examples/production-ready/03-data-analysis-agent/openapi.yaml +74 -0
  455. package/examples/production-ready/04-content-moderator/README.md +55 -0
  456. package/examples/production-ready/04-content-moderator/agent.ossa.yaml +131 -0
  457. package/examples/production-ready/04-content-moderator/openapi.yaml +50 -0
  458. package/examples/production-ready/05-sales-assistant/README.md +37 -0
  459. package/examples/production-ready/05-sales-assistant/agent.ossa.yaml +146 -0
  460. package/examples/production-ready/05-sales-assistant/openapi.yaml +59 -0
  461. package/examples/production-ready/06-devops-agent/README.md +39 -0
  462. package/examples/production-ready/06-devops-agent/agent.ossa.yaml +141 -0
  463. package/examples/production-ready/06-devops-agent/openapi.yaml +51 -0
  464. package/examples/production-ready/07-research-assistant/README.md +31 -0
  465. package/examples/production-ready/07-research-assistant/agent.ossa.yaml +119 -0
  466. package/examples/production-ready/07-research-assistant/openapi.yaml +56 -0
  467. package/examples/production-ready/08-email-triage-agent/README.md +33 -0
  468. package/examples/production-ready/08-email-triage-agent/agent.ossa.yaml +133 -0
  469. package/examples/production-ready/08-email-triage-agent/openapi.yaml +41 -0
  470. package/examples/production-ready/09-security-scanner/README.md +49 -0
  471. package/examples/production-ready/09-security-scanner/agent.ossa.yaml +174 -0
  472. package/examples/production-ready/09-security-scanner/openapi.yaml +46 -0
  473. package/examples/production-ready/10-meeting-assistant/README.md +53 -0
  474. package/examples/production-ready/10-meeting-assistant/agent.ossa.yaml +211 -0
  475. package/examples/production-ready/10-meeting-assistant/docker-compose.yml +27 -0
  476. package/examples/production-ready/10-meeting-assistant/openapi.yaml +131 -0
  477. package/examples/production-ready/COMPLETION_REPORT.txt +272 -0
  478. package/examples/production-ready/INDEX.md +296 -0
  479. package/examples/production-ready/README.md +452 -0
  480. package/examples/production-ready/SUMMARY.md +362 -0
  481. package/examples/production-ready/TEST_RESULTS.md +458 -0
  482. package/examples/quickstart/support-agent.ossa.yaml +1 -1
  483. package/examples/real-world/gitlab-cicd-optimizer.ossa.yaml +1 -1
  484. package/examples/real-world/rag-documentation-assistant.ossa.yaml +1 -1
  485. package/examples/registry/agents/code-reviewer/agent.yaml +1 -1
  486. package/examples/registry/agents/security-scanner/agent.yaml +1 -1
  487. package/examples/runtime-adapters/bedrock-claude-example.ossa.yaml +1 -1
  488. package/examples/schema/reusable-components.yaml +1 -1
  489. package/examples/showcase/ci-pipeline.ossa.yaml +1 -1
  490. package/examples/showcase/code-assistant.ossa.yaml +1 -1
  491. package/examples/showcase/code-reviewer.ossa.yaml +1 -1
  492. package/examples/showcase/compliance-validator.ossa.yaml +1 -1
  493. package/examples/showcase/content-writer.ossa.yaml +1 -1
  494. package/examples/showcase/data-transformer.ossa.yaml +1 -1
  495. package/examples/showcase/doc-generator.ossa.yaml +1 -1
  496. package/examples/showcase/security-scanner.ossa.yaml +1 -1
  497. package/examples/showcase/test-generator.ossa.yaml +1 -1
  498. package/examples/showcase/workflow-orchestrator.ossa.yaml +1 -1
  499. package/examples/skills-example.ossa.yaml +140 -0
  500. package/examples/swarm/pso-optimizer.ossa.json +1 -1
  501. package/examples/tasks/batch-email-sender.yaml +1 -1
  502. package/examples/tasks/data-transform.yaml +1 -1
  503. package/examples/tasks/publish-content.yaml +1 -1
  504. package/examples/templates/ossa-compliance.yaml +1 -1
  505. package/examples/unified/security-scanner.ossa.yaml +1 -1
  506. package/examples/v0.3.6-features/genetics-breeding-advanced.ossa.yaml +1 -1
  507. package/examples/v0.3.6-features/genetics-breeding-simple.ossa.yaml +1 -1
  508. package/examples/v0.3.6-features/genetics-fitness-scoring.ossa.yaml +1 -1
  509. package/examples/vercel/edge-agent.ossa.json +1 -1
  510. package/examples/workflows/batch-email-campaign.yaml +1 -1
  511. package/examples/workflows/content-review-publish.yaml +1 -1
  512. package/examples/workflows/simple-etl.yaml +1 -1
  513. package/openapi/cli/openapi.yaml +221 -5
  514. package/package.json +31 -9
  515. package/dist/cli/commands/export-v2.command.d.ts +0 -7
  516. package/dist/cli/commands/export-v2.command.d.ts.map +0 -1
  517. 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