@webiny/ai-powerups 6.6.0-alpha.4 → 6.6.0-alpha.6

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 (211) hide show
  1. package/AiPowerups.d.ts +12 -0
  2. package/AiPowerups.js +1 -2
  3. package/AiPowerups.js.map +1 -1
  4. package/admin/Extension.d.ts +1 -1
  5. package/admin/Extension.js +6 -2
  6. package/admin/Extension.js.map +1 -1
  7. package/admin/domain/modelRoles.d.ts +17 -0
  8. package/admin/domain/modelRoles.js +8 -0
  9. package/admin/domain/modelRoles.js.map +1 -0
  10. package/admin/features/feature.js +2 -0
  11. package/admin/features/feature.js.map +1 -1
  12. package/admin/features/listCapabilities/ListCapabilitiesGateway.d.ts +12 -0
  13. package/admin/features/listCapabilities/ListCapabilitiesGateway.js +34 -0
  14. package/admin/features/listCapabilities/ListCapabilitiesGateway.js.map +1 -0
  15. package/admin/features/listCapabilities/ListCapabilitiesRepository.d.ts +13 -0
  16. package/admin/features/listCapabilities/ListCapabilitiesRepository.js +27 -0
  17. package/admin/features/listCapabilities/ListCapabilitiesRepository.js.map +1 -0
  18. package/admin/features/listCapabilities/ListCapabilitiesUseCase.d.ts +10 -0
  19. package/admin/features/listCapabilities/ListCapabilitiesUseCase.js +18 -0
  20. package/admin/features/listCapabilities/ListCapabilitiesUseCase.js.map +1 -0
  21. package/admin/features/listCapabilities/abstractions.d.ts +28 -0
  22. package/admin/features/listCapabilities/abstractions.js +7 -0
  23. package/admin/features/listCapabilities/abstractions.js.map +1 -0
  24. package/admin/features/listCapabilities/feature.d.ts +3 -0
  25. package/admin/features/listCapabilities/feature.js +21 -0
  26. package/admin/features/listCapabilities/feature.js.map +1 -0
  27. package/admin/features/listCapabilities/index.d.ts +3 -0
  28. package/admin/features/listCapabilities/index.js +2 -0
  29. package/admin/features/settings/shared/abstractions.d.ts +58 -25
  30. package/admin/features/settings/shared/abstractions.js.map +1 -1
  31. package/admin/presentation/AiPowerUpsSettings/AiPowerUpsSettingsPresenter.js +13 -1
  32. package/admin/presentation/AiPowerUpsSettings/AiPowerUpsSettingsPresenter.js.map +1 -1
  33. package/admin/presentation/AiPowerUpsSettings/feature.js +6 -2
  34. package/admin/presentation/AiPowerUpsSettings/feature.js.map +1 -1
  35. package/admin/presentation/AiPowerUpsSettings/hasUsableModel.d.ts +13 -0
  36. package/admin/presentation/AiPowerUpsSettings/hasUsableModel.js +9 -0
  37. package/admin/presentation/AiPowerUpsSettings/hasUsableModel.js.map +1 -0
  38. package/admin/presentation/AiPowerUpsSettings/index.d.ts +1 -0
  39. package/admin/presentation/AiPowerUpsSettings/index.js +1 -0
  40. package/admin/presentation/AiPowerUpsSettings/settingsGroup.d.ts +9 -0
  41. package/admin/presentation/AiPowerUpsSettings/settingsGroup.js.map +1 -1
  42. package/admin/presentation/CapabilitiesSettings.d.ts +39 -0
  43. package/admin/presentation/CapabilitiesSettings.js +104 -0
  44. package/admin/presentation/CapabilitiesSettings.js.map +1 -0
  45. package/admin/presentation/CmsContentGeneration/CmsGenerateContentButton.js +2 -2
  46. package/admin/presentation/CmsContentGeneration/CmsGenerateContentButton.js.map +1 -1
  47. package/admin/presentation/ConnectionsSettings.d.ts +25 -0
  48. package/admin/presentation/ConnectionsSettings.js +52 -0
  49. package/admin/presentation/ConnectionsSettings.js.map +1 -0
  50. package/admin/presentation/ModelRolesSettings.d.ts +29 -0
  51. package/admin/presentation/ModelRolesSettings.js +67 -0
  52. package/admin/presentation/ModelRolesSettings.js.map +1 -0
  53. package/admin/presentation/WbContentGeneration/GenerateContentButton.js +2 -2
  54. package/admin/presentation/WbContentGeneration/GenerateContentButton.js.map +1 -1
  55. package/admin/presentation/modelRoles.d.ts +10 -0
  56. package/admin/presentation/modelRoles.js +23 -0
  57. package/admin/presentation/modelRoles.js.map +1 -0
  58. package/api/Extension.js +10 -2
  59. package/api/Extension.js.map +1 -1
  60. package/api/features/AdminAssistant/AdminAssistantStreamRoute.d.ts +34 -0
  61. package/api/features/AdminAssistant/AdminAssistantStreamRoute.js +42 -0
  62. package/api/features/AdminAssistant/AdminAssistantStreamRoute.js.map +1 -0
  63. package/api/features/AdminAssistant/AdminAssistantUseCase.d.ts +42 -0
  64. package/api/features/AdminAssistant/AdminAssistantUseCase.js +170 -0
  65. package/api/features/AdminAssistant/AdminAssistantUseCase.js.map +1 -0
  66. package/api/features/AdminAssistant/abstractions.d.ts +38 -0
  67. package/api/features/AdminAssistant/abstractions.js +6 -0
  68. package/api/features/AdminAssistant/abstractions.js.map +1 -0
  69. package/api/features/AdminAssistant/approvals.d.ts +29 -0
  70. package/api/features/AdminAssistant/approvals.js +30 -0
  71. package/api/features/AdminAssistant/approvals.js.map +1 -0
  72. package/api/features/AdminAssistant/capability.d.ts +31 -0
  73. package/api/features/AdminAssistant/capability.js +19 -0
  74. package/api/features/AdminAssistant/capability.js.map +1 -0
  75. package/api/features/AdminAssistant/events.d.ts +54 -0
  76. package/api/features/AdminAssistant/events.js +0 -0
  77. package/api/features/AdminAssistant/feature.d.ts +12 -0
  78. package/api/features/AdminAssistant/feature.js +23 -0
  79. package/api/features/AdminAssistant/feature.js.map +1 -0
  80. package/api/features/AdminAssistant/index.d.ts +5 -0
  81. package/api/features/AdminAssistant/index.js +3 -0
  82. package/api/features/AdminAssistant/parseChatBody.d.ts +14 -0
  83. package/api/features/AdminAssistant/parseChatBody.js +33 -0
  84. package/api/features/AdminAssistant/parseChatBody.js.map +1 -0
  85. package/api/features/AdminAssistant/systemPrompt.d.ts +7 -0
  86. package/api/features/AdminAssistant/systemPrompt.js +24 -0
  87. package/api/features/AdminAssistant/systemPrompt.js.map +1 -0
  88. package/api/features/AiImageEnrichment/PrepareImageEnrichmentUseCase.d.ts +3 -5
  89. package/api/features/AiImageEnrichment/PrepareImageEnrichmentUseCase.js +11 -16
  90. package/api/features/AiImageEnrichment/PrepareImageEnrichmentUseCase.js.map +1 -1
  91. package/api/features/AiImageEnrichment/abstractions.d.ts +6 -0
  92. package/api/features/AiImageEnrichment/abstractions.js.map +1 -1
  93. package/api/features/AiImageEnrichment/buildEnrichmentAiRequest.js +2 -2
  94. package/api/features/AiImageEnrichment/buildEnrichmentAiRequest.js.map +1 -1
  95. package/api/features/AiImageEnrichment/capability.d.ts +18 -0
  96. package/api/features/AiImageEnrichment/capability.js +19 -0
  97. package/api/features/AiImageEnrichment/capability.js.map +1 -0
  98. package/api/features/AiImageEnrichment/errors.d.ts +6 -1
  99. package/api/features/AiImageEnrichment/errors.js +2 -2
  100. package/api/features/AiImageEnrichment/errors.js.map +1 -1
  101. package/api/features/AiImageEnrichment/feature.js +2 -0
  102. package/api/features/AiImageEnrichment/feature.js.map +1 -1
  103. package/api/features/Capabilities/CapabilitiesHandler.d.ts +28 -0
  104. package/api/features/Capabilities/CapabilitiesHandler.js +56 -0
  105. package/api/features/Capabilities/CapabilitiesHandler.js.map +1 -0
  106. package/api/features/Capabilities/ListAiCapabilitiesUseCase.d.ts +18 -0
  107. package/api/features/Capabilities/ListAiCapabilitiesUseCase.js +28 -0
  108. package/api/features/Capabilities/ListAiCapabilitiesUseCase.js.map +1 -0
  109. package/api/features/Capabilities/ResolveAiCapabilityUseCase.d.ts +30 -0
  110. package/api/features/Capabilities/ResolveAiCapabilityUseCase.js +88 -0
  111. package/api/features/Capabilities/ResolveAiCapabilityUseCase.js.map +1 -0
  112. package/api/features/Capabilities/abstractions.d.ts +77 -0
  113. package/api/features/Capabilities/abstractions.js +7 -0
  114. package/api/features/Capabilities/abstractions.js.map +1 -0
  115. package/api/features/Capabilities/composeSystemPrompt.d.ts +14 -0
  116. package/api/features/Capabilities/composeSystemPrompt.js +13 -0
  117. package/api/features/Capabilities/composeSystemPrompt.js.map +1 -0
  118. package/api/features/Capabilities/feature.d.ts +4 -0
  119. package/api/features/Capabilities/feature.js +15 -0
  120. package/api/features/Capabilities/feature.js.map +1 -0
  121. package/api/features/Capabilities/index.d.ts +5 -0
  122. package/api/features/Capabilities/index.js +3 -0
  123. package/api/features/Capabilities/types.d.ts +86 -0
  124. package/api/features/Capabilities/types.js +4 -0
  125. package/api/features/Capabilities/types.js.map +1 -0
  126. package/api/features/CmsCompareEntryRevisions/CmsCompareEntryRevisionsUseCase.d.ts +3 -5
  127. package/api/features/CmsCompareEntryRevisions/CmsCompareEntryRevisionsUseCase.js +11 -65
  128. package/api/features/CmsCompareEntryRevisions/CmsCompareEntryRevisionsUseCase.js.map +1 -1
  129. package/api/features/CmsCompareEntryRevisions/capability.d.ts +13 -0
  130. package/api/features/CmsCompareEntryRevisions/capability.js +64 -0
  131. package/api/features/CmsCompareEntryRevisions/capability.js.map +1 -0
  132. package/api/features/CmsCompareEntryRevisions/feature.js +2 -0
  133. package/api/features/CmsCompareEntryRevisions/feature.js.map +1 -1
  134. package/api/features/CmsGenerateEntryContent/CmsGenerateEntryContentUseCase.d.ts +3 -5
  135. package/api/features/CmsGenerateEntryContent/CmsGenerateEntryContentUseCase.js +11 -19
  136. package/api/features/CmsGenerateEntryContent/CmsGenerateEntryContentUseCase.js.map +1 -1
  137. package/api/features/CmsGenerateEntryContent/capability.d.ts +17 -0
  138. package/api/features/CmsGenerateEntryContent/capability.js +17 -0
  139. package/api/features/CmsGenerateEntryContent/capability.js.map +1 -0
  140. package/api/features/CmsGenerateEntryContent/feature.js +2 -0
  141. package/api/features/CmsGenerateEntryContent/feature.js.map +1 -1
  142. package/api/features/Connections/ConnectionsGraphQLMapper.d.ts +20 -0
  143. package/api/features/Connections/ConnectionsGraphQLMapper.js +37 -0
  144. package/api/features/Connections/ConnectionsGraphQLMapper.js.map +1 -0
  145. package/api/features/Connections/ConnectionsHandler.d.ts +25 -0
  146. package/api/features/Connections/ConnectionsHandler.js +84 -0
  147. package/api/features/Connections/ConnectionsHandler.js.map +1 -0
  148. package/api/features/Connections/feature.d.ts +4 -0
  149. package/api/features/Connections/feature.js +13 -0
  150. package/api/features/Connections/feature.js.map +1 -0
  151. package/api/features/Connections/index.d.ts +2 -0
  152. package/api/features/Connections/index.js +1 -0
  153. package/api/features/Connections/legacyProviders.d.ts +26 -0
  154. package/api/features/Connections/legacyProviders.js +9 -0
  155. package/api/features/Connections/legacyProviders.js.map +1 -0
  156. package/api/features/Connections/types.d.ts +36 -0
  157. package/api/features/Connections/types.js +0 -0
  158. package/api/features/GetSettings/GetSettingsRepository.js +1 -1
  159. package/api/features/GetSettings/GetSettingsRepository.js.map +1 -1
  160. package/api/features/ModelRoles/ModelRolesHandler.d.ts +15 -0
  161. package/api/features/ModelRoles/ModelRolesHandler.js +68 -0
  162. package/api/features/ModelRoles/ModelRolesHandler.js.map +1 -0
  163. package/api/features/ModelRoles/feature.d.ts +4 -0
  164. package/api/features/ModelRoles/feature.js +11 -0
  165. package/api/features/ModelRoles/feature.js.map +1 -0
  166. package/api/features/ModelRoles/index.d.ts +4 -0
  167. package/api/features/ModelRoles/index.js +2 -0
  168. package/api/features/ModelRoles/roles.d.ts +16 -0
  169. package/api/features/ModelRoles/roles.js +9 -0
  170. package/api/features/ModelRoles/roles.js.map +1 -0
  171. package/api/features/ModelRoles/types.d.ts +21 -0
  172. package/api/features/ModelRoles/types.js +7 -0
  173. package/api/features/ModelRoles/types.js.map +1 -0
  174. package/api/features/UpdateSettings/UpdateSettingsRepository.js +2 -2
  175. package/api/features/UpdateSettings/UpdateSettingsRepository.js.map +1 -1
  176. package/api/features/WbGeneratePageContent/WbGeneratePageContentUseCase.d.ts +3 -5
  177. package/api/features/WbGeneratePageContent/WbGeneratePageContentUseCase.js +11 -19
  178. package/api/features/WbGeneratePageContent/WbGeneratePageContentUseCase.js.map +1 -1
  179. package/api/features/WbGeneratePageContent/capability.d.ts +16 -0
  180. package/api/features/WbGeneratePageContent/capability.js +17 -0
  181. package/api/features/WbGeneratePageContent/capability.js.map +1 -0
  182. package/api/features/WbGeneratePageContent/feature.js +2 -0
  183. package/api/features/WbGeneratePageContent/feature.js.map +1 -1
  184. package/api/features/WbTranslatePage/WbTranslatePageDecorator.d.ts +5 -5
  185. package/api/features/WbTranslatePage/WbTranslatePageDecorator.js +19 -19
  186. package/api/features/WbTranslatePage/WbTranslatePageDecorator.js.map +1 -1
  187. package/api/features/WbTranslatePage/capability.d.ts +13 -0
  188. package/api/features/WbTranslatePage/capability.js +19 -0
  189. package/api/features/WbTranslatePage/capability.js.map +1 -0
  190. package/api/features/WbTranslatePage/feature.js +2 -0
  191. package/api/features/WbTranslatePage/feature.js.map +1 -1
  192. package/api/features/shared/abstractions.d.ts +6 -1
  193. package/api/features/shared/abstractions.js.map +1 -1
  194. package/api/features/shared/modelId.d.ts +11 -0
  195. package/api/features/shared/modelId.js +4 -0
  196. package/api/features/shared/modelId.js.map +1 -0
  197. package/api/graphql/BaseGraphQLSchema.js +16 -0
  198. package/api/graphql/BaseGraphQLSchema.js.map +1 -1
  199. package/api/types.d.ts +3 -0
  200. package/api/types.js +3 -0
  201. package/exports/api/ai-powerups.d.ts +5 -0
  202. package/exports/api/ai-powerups.js +3 -0
  203. package/package.json +24 -26
  204. package/api/features/AiChatProvider/PowerUpsAiChatProvider.d.ts +0 -24
  205. package/api/features/AiChatProvider/PowerUpsAiChatProvider.js +0 -31
  206. package/api/features/AiChatProvider/PowerUpsAiChatProvider.js.map +0 -1
  207. package/api/features/AiChatProvider/feature.d.ts +0 -9
  208. package/api/features/AiChatProvider/feature.js +0 -11
  209. package/api/features/AiChatProvider/feature.js.map +0 -1
  210. package/api/features/AiChatProvider/index.d.ts +0 -2
  211. package/api/features/AiChatProvider/index.js +0 -2
package/api/Extension.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { createFeature } from "@webiny/feature/api";
2
+ import { FeatureFlags } from "@webiny/api-core/features/featureFlags/abstractions.js";
2
3
  import { BaseGraphQLSchema } from "./graphql/BaseGraphQLSchema.js";
3
4
  import AiPowerUpsSettingsGraphQLMapper from "./graphql/AiPowerUpsSettingsGraphQLMapper.js";
4
5
  import { AiPowerUpsSettingsCache } from "./features/shared/SettingsCache.js";
@@ -6,6 +7,9 @@ import { GetSettingsFeature } from "./features/GetSettings/feature.js";
6
7
  import { UpdateSettingsFeature } from "./features/UpdateSettings/feature.js";
7
8
  import { WbGeneratePageContentFeature } from "./features/WbGeneratePageContent/feature.js";
8
9
  import { ProvidersFeature } from "./features/Providers/feature.js";
10
+ import { ConnectionsFeature } from "./features/Connections/feature.js";
11
+ import { ModelRolesFeature } from "./features/ModelRoles/feature.js";
12
+ import { CapabilitiesFeature } from "./features/Capabilities/feature.js";
9
13
  import { ReaderPersonasFeature } from "./features/ReaderPersonas/feature.js";
10
14
  import { WriterPersonasFeature } from "./features/WriterPersonas/feature.js";
11
15
  import { ProjectsFeature } from "./features/Projects/feature.js";
@@ -14,17 +18,21 @@ import { AiImageEnrichmentFeature } from "./features/AiImageEnrichment/feature.j
14
18
  import { ExtractFrontmatterFeature } from "./features/ExtractFrontmatter/feature.js";
15
19
  import { CmsGenerateEntryContentFeature } from "./features/CmsGenerateEntryContent/feature.js";
16
20
  import { CmsResolveImageToolFeature } from "./features/CmsResolveImageTool/feature.js";
17
- import { AiChatProviderFeature } from "./features/AiChatProvider/index.js";
21
+ import { AdminAssistantFeature } from "./features/AdminAssistant/index.js";
18
22
  import { CmsCompareEntryRevisionsFeature } from "./features/CmsCompareEntryRevisions/feature.js";
19
23
  import { WbTranslatePageFeature } from "./features/WbTranslatePage/feature.js";
20
24
  import { CmsCompareEntryRevisionsSchema } from "./graphql/CmsCompareEntryRevisionsSchema.js";
21
25
  const Extension = createFeature({
22
26
  name: "AiPowerUps",
23
27
  register (container) {
28
+ if (!container.resolve(FeatureFlags).get().isEnabled("aiPowerups")) return;
24
29
  container.register(AiPowerUpsSettingsCache).inSingletonScope();
25
30
  GetSettingsFeature.register(container);
26
31
  UpdateSettingsFeature.register(container);
27
32
  ProvidersFeature.register(container);
33
+ ConnectionsFeature.register(container);
34
+ ModelRolesFeature.register(container);
35
+ CapabilitiesFeature.register(container);
28
36
  ReaderPersonasFeature.register(container);
29
37
  WriterPersonasFeature.register(container);
30
38
  ProjectsFeature.register(container);
@@ -32,7 +40,7 @@ const Extension = createFeature({
32
40
  WbGeneratePageContentFeature.register(container);
33
41
  CmsGenerateEntryContentFeature.register(container);
34
42
  CmsResolveImageToolFeature.register(container);
35
- AiChatProviderFeature.register(container);
43
+ AdminAssistantFeature.register(container);
36
44
  ExtractFrontmatterFeature.register(container);
37
45
  AiImageEnrichmentFeature.register(container);
38
46
  CmsCompareEntryRevisionsFeature.register(container);
@@ -1 +1 @@
1
- {"version":3,"file":"api/Extension.js","sources":["../../src/api/Extension.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { BaseGraphQLSchema } from \"./graphql/BaseGraphQLSchema.js\";\nimport AiPowerUpsSettingsGraphQLMapperImpl from \"./graphql/AiPowerUpsSettingsGraphQLMapper.js\";\nimport { AiPowerUpsSettingsCache } from \"./features/shared/SettingsCache.js\";\nimport { GetSettingsFeature } from \"./features/GetSettings/feature.js\";\nimport { UpdateSettingsFeature } from \"./features/UpdateSettings/feature.js\";\nimport { WbGeneratePageContentFeature } from \"./features/WbGeneratePageContent/feature.js\";\nimport { ProvidersFeature } from \"./features/Providers/feature.js\";\nimport { ReaderPersonasFeature } from \"./features/ReaderPersonas/feature.js\";\nimport { WriterPersonasFeature } from \"./features/WriterPersonas/feature.js\";\nimport { ProjectsFeature } from \"./features/Projects/feature.js\";\nimport { AiPromptContextFeature } from \"./features/AiPromptContext/feature.js\";\nimport { AiImageEnrichmentFeature } from \"./features/AiImageEnrichment/feature.js\";\nimport { ExtractFrontmatterFeature } from \"./features/ExtractFrontmatter/feature.js\";\nimport { CmsGenerateEntryContentFeature } from \"./features/CmsGenerateEntryContent/feature.js\";\nimport { CmsResolveImageToolFeature } from \"./features/CmsResolveImageTool/feature.js\";\nimport { AiChatProviderFeature } from \"./features/AiChatProvider/index.js\";\nimport { CmsCompareEntryRevisionsFeature } from \"./features/CmsCompareEntryRevisions/feature.js\";\nimport { WbTranslatePageFeature } from \"./features/WbTranslatePage/feature.js\";\nimport { CmsCompareEntryRevisionsSchema } from \"./graphql/CmsCompareEntryRevisionsSchema.js\";\n\nexport const Extension = createFeature({\n name: \"AiPowerUps\",\n register(container) {\n container.register(AiPowerUpsSettingsCache).inSingletonScope();\n\n GetSettingsFeature.register(container);\n UpdateSettingsFeature.register(container);\n ProvidersFeature.register(container);\n ReaderPersonasFeature.register(container);\n WriterPersonasFeature.register(container);\n ProjectsFeature.register(container);\n AiPromptContextFeature.register(container);\n WbGeneratePageContentFeature.register(container);\n CmsGenerateEntryContentFeature.register(container);\n CmsResolveImageToolFeature.register(container);\n AiChatProviderFeature.register(container);\n ExtractFrontmatterFeature.register(container);\n\n // Registered unconditionally. The WCP license gate lives inside the feature's\n // FileAfterCreate handler (trigger-time), because the license isn't loaded yet during this\n // register() phase — a register-time canUse* check reads NullLicense and is always false.\n AiImageEnrichmentFeature.register(container);\n\n CmsCompareEntryRevisionsFeature.register(container);\n WbTranslatePageFeature.register(container);\n\n container.register(AiPowerUpsSettingsGraphQLMapperImpl).inSingletonScope();\n container.register(BaseGraphQLSchema);\n container.register(CmsCompareEntryRevisionsSchema);\n }\n});\n"],"names":["Extension","createFeature","container","AiPowerUpsSettingsCache","GetSettingsFeature","UpdateSettingsFeature","ProvidersFeature","ReaderPersonasFeature","WriterPersonasFeature","ProjectsFeature","AiPromptContextFeature","WbGeneratePageContentFeature","CmsGenerateEntryContentFeature","CmsResolveImageToolFeature","AiChatProviderFeature","ExtractFrontmatterFeature","AiImageEnrichmentFeature","CmsCompareEntryRevisionsFeature","WbTranslatePageFeature","AiPowerUpsSettingsGraphQLMapperImpl","BaseGraphQLSchema","CmsCompareEntryRevisionsSchema"],"mappings":";;;;;;;;;;;;;;;;;;;;AAqBO,MAAMA,YAAYC,cAAc;IACnC,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC,yBAAyB,gBAAgB;QAE5DC,mBAAmB,QAAQ,CAACF;QAC5BG,sBAAsB,QAAQ,CAACH;QAC/BI,iBAAiB,QAAQ,CAACJ;QAC1BK,sBAAsB,QAAQ,CAACL;QAC/BM,sBAAsB,QAAQ,CAACN;QAC/BO,gBAAgB,QAAQ,CAACP;QACzBQ,uBAAuB,QAAQ,CAACR;QAChCS,6BAA6B,QAAQ,CAACT;QACtCU,+BAA+B,QAAQ,CAACV;QACxCW,2BAA2B,QAAQ,CAACX;QACpCY,sBAAsB,QAAQ,CAACZ;QAC/Ba,0BAA0B,QAAQ,CAACb;QAKnCc,yBAAyB,QAAQ,CAACd;QAElCe,gCAAgC,QAAQ,CAACf;QACzCgB,uBAAuB,QAAQ,CAAChB;QAEhCA,UAAU,QAAQ,CAACiB,iCAAqC,gBAAgB;QACxEjB,UAAU,QAAQ,CAACkB;QACnBlB,UAAU,QAAQ,CAACmB;IACvB;AACJ"}
1
+ {"version":3,"file":"api/Extension.js","sources":["../../src/api/Extension.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { FeatureFlags } from \"@webiny/api-core/features/featureFlags/abstractions.js\";\nimport { BaseGraphQLSchema } from \"./graphql/BaseGraphQLSchema.js\";\nimport AiPowerUpsSettingsGraphQLMapperImpl from \"./graphql/AiPowerUpsSettingsGraphQLMapper.js\";\nimport { AiPowerUpsSettingsCache } from \"./features/shared/SettingsCache.js\";\nimport { GetSettingsFeature } from \"./features/GetSettings/feature.js\";\nimport { UpdateSettingsFeature } from \"./features/UpdateSettings/feature.js\";\nimport { WbGeneratePageContentFeature } from \"./features/WbGeneratePageContent/feature.js\";\nimport { ProvidersFeature } from \"./features/Providers/feature.js\";\nimport { ConnectionsFeature } from \"./features/Connections/feature.js\";\nimport { ModelRolesFeature } from \"./features/ModelRoles/feature.js\";\nimport { CapabilitiesFeature } from \"./features/Capabilities/feature.js\";\nimport { ReaderPersonasFeature } from \"./features/ReaderPersonas/feature.js\";\nimport { WriterPersonasFeature } from \"./features/WriterPersonas/feature.js\";\nimport { ProjectsFeature } from \"./features/Projects/feature.js\";\nimport { AiPromptContextFeature } from \"./features/AiPromptContext/feature.js\";\nimport { AiImageEnrichmentFeature } from \"./features/AiImageEnrichment/feature.js\";\nimport { ExtractFrontmatterFeature } from \"./features/ExtractFrontmatter/feature.js\";\nimport { CmsGenerateEntryContentFeature } from \"./features/CmsGenerateEntryContent/feature.js\";\nimport { CmsResolveImageToolFeature } from \"./features/CmsResolveImageTool/feature.js\";\nimport { AdminAssistantFeature } from \"./features/AdminAssistant/index.js\";\nimport { CmsCompareEntryRevisionsFeature } from \"./features/CmsCompareEntryRevisions/feature.js\";\nimport { WbTranslatePageFeature } from \"./features/WbTranslatePage/feature.js\";\nimport { CmsCompareEntryRevisionsSchema } from \"./graphql/CmsCompareEntryRevisionsSchema.js\";\n\nexport const Extension = createFeature({\n name: \"AiPowerUps\",\n register(container) {\n /*\n * The whole extension is gated here rather than around `<Api.Extension>` in\n * `AiPowerups.tsx`. That wrapper read project config while the project graph was built, so\n * a licence bought after the last deploy did nothing until the next one.\n *\n * Register time is early enough and the flags are correct here: `registerApiRequestStack`\n * refreshes the WCP licence before any feature registers, so `isEnabled` sees the effective\n * flags (project config && live licence). `AcoFeature` and `AiChatFeature` gate the same\n * way.\n *\n * Nothing is registered when it is off, so a project without AI Power-Ups has no settings\n * schema and no capability resolver at all, rather than ones that fail on use. Anything\n * outside this extension that wants a capability must therefore declare\n * `[ResolveAiCapabilityUseCase, { optional: true }]` and handle its absence.\n */\n if (!container.resolve(FeatureFlags).get().isEnabled(\"aiPowerups\")) {\n return;\n }\n\n container.register(AiPowerUpsSettingsCache).inSingletonScope();\n\n GetSettingsFeature.register(container);\n UpdateSettingsFeature.register(container);\n /*\n * `ProvidersFeature` is still registered so the legacy `providers` section keeps round-\n * tripping through storage. `Connections` and `ModelRoles` read it once to seed\n * themselves; nothing else does. It goes away with the next breaking release.\n */\n ProvidersFeature.register(container);\n ConnectionsFeature.register(container);\n ModelRolesFeature.register(container);\n CapabilitiesFeature.register(container);\n ReaderPersonasFeature.register(container);\n WriterPersonasFeature.register(container);\n ProjectsFeature.register(container);\n AiPromptContextFeature.register(container);\n WbGeneratePageContentFeature.register(container);\n CmsGenerateEntryContentFeature.register(container);\n CmsResolveImageToolFeature.register(container);\n AdminAssistantFeature.register(container);\n ExtractFrontmatterFeature.register(container);\n\n // Registered unconditionally. The WCP license gate lives inside the feature's\n // FileAfterCreate handler (trigger-time), because the license isn't loaded yet during this\n // register() phase — a register-time canUse* check reads NullLicense and is always false.\n AiImageEnrichmentFeature.register(container);\n\n CmsCompareEntryRevisionsFeature.register(container);\n WbTranslatePageFeature.register(container);\n\n container.register(AiPowerUpsSettingsGraphQLMapperImpl).inSingletonScope();\n container.register(BaseGraphQLSchema);\n container.register(CmsCompareEntryRevisionsSchema);\n }\n});\n"],"names":["Extension","createFeature","container","FeatureFlags","AiPowerUpsSettingsCache","GetSettingsFeature","UpdateSettingsFeature","ProvidersFeature","ConnectionsFeature","ModelRolesFeature","CapabilitiesFeature","ReaderPersonasFeature","WriterPersonasFeature","ProjectsFeature","AiPromptContextFeature","WbGeneratePageContentFeature","CmsGenerateEntryContentFeature","CmsResolveImageToolFeature","AdminAssistantFeature","ExtractFrontmatterFeature","AiImageEnrichmentFeature","CmsCompareEntryRevisionsFeature","WbTranslatePageFeature","AiPowerUpsSettingsGraphQLMapperImpl","BaseGraphQLSchema","CmsCompareEntryRevisionsSchema"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAyBO,MAAMA,YAAYC,cAAc;IACnC,MAAM;IACN,UAASC,SAAS;QAgBd,IAAI,CAACA,UAAU,OAAO,CAACC,cAAc,GAAG,GAAG,SAAS,CAAC,eACjD;QAGJD,UAAU,QAAQ,CAACE,yBAAyB,gBAAgB;QAE5DC,mBAAmB,QAAQ,CAACH;QAC5BI,sBAAsB,QAAQ,CAACJ;QAM/BK,iBAAiB,QAAQ,CAACL;QAC1BM,mBAAmB,QAAQ,CAACN;QAC5BO,kBAAkB,QAAQ,CAACP;QAC3BQ,oBAAoB,QAAQ,CAACR;QAC7BS,sBAAsB,QAAQ,CAACT;QAC/BU,sBAAsB,QAAQ,CAACV;QAC/BW,gBAAgB,QAAQ,CAACX;QACzBY,uBAAuB,QAAQ,CAACZ;QAChCa,6BAA6B,QAAQ,CAACb;QACtCc,+BAA+B,QAAQ,CAACd;QACxCe,2BAA2B,QAAQ,CAACf;QACpCgB,sBAAsB,QAAQ,CAAChB;QAC/BiB,0BAA0B,QAAQ,CAACjB;QAKnCkB,yBAAyB,QAAQ,CAAClB;QAElCmB,gCAAgC,QAAQ,CAACnB;QACzCoB,uBAAuB,QAAQ,CAACpB;QAEhCA,UAAU,QAAQ,CAACqB,iCAAqC,gBAAgB;QACxErB,UAAU,QAAQ,CAACsB;QACnBtB,UAAU,QAAQ,CAACuB;IACvB;AACJ"}
@@ -0,0 +1,34 @@
1
+ import { HttpRouteDefinition, HttpRouteHandler } from "@webiny/event-handler-core";
2
+ import type { IHttpRequest, IHttpResponseBuilder } from "@webiny/event-handler-core";
3
+ import { AdminAssistantUseCase } from "./abstractions.js";
4
+ /**
5
+ * `POST /stream/ai/admin-assistant`, reported as it works rather than all at once.
6
+ *
7
+ * A separate route rather than a flag on the buffered one: the two have genuinely different response
8
+ * contracts (one JSON object versus an event stream), so a client picks which it wants by the URL it
9
+ * calls, and the buffered route stays available for callers that cannot read a stream.
10
+ *
11
+ * Failures after the first byte cannot become a status code, since the response has already committed
12
+ * to 200, so the use case reports them as `error` events and the stream ends normally.
13
+ */
14
+ declare class AdminAssistantStreamRouteImpl implements HttpRouteHandler.Interface {
15
+ private readonly assistant;
16
+ constructor(assistant: AdminAssistantUseCase.Interface);
17
+ handle(request: IHttpRequest, response: IHttpResponseBuilder): Promise<IHttpResponseBuilder>;
18
+ }
19
+ export declare const AdminAssistantStreamRoute: typeof AdminAssistantStreamRouteImpl & {
20
+ __abstraction: import("@webiny/di").Abstraction<import("@webiny/event-handler-core").IHttpRoute>;
21
+ };
22
+ declare class AdminAssistantStreamRouteDefinitionImpl implements HttpRouteDefinition.Interface {
23
+ readonly name = "admin-assistant-stream";
24
+ readonly method = "POST";
25
+ readonly path = "/stream/ai/admin-assistant";
26
+ readonly handler: typeof AdminAssistantStreamRouteImpl & {
27
+ __abstraction: import("@webiny/di").Abstraction<import("@webiny/event-handler-core").IHttpRoute>;
28
+ };
29
+ }
30
+ /** What the router matches on. Zero dependencies, so building it costs nothing. */
31
+ export declare const AdminAssistantStreamRouteDefinition: typeof AdminAssistantStreamRouteDefinitionImpl & {
32
+ __abstraction: import("@webiny/di").Abstraction<import("@webiny/event-handler-core").IHttpRouteDefinition>;
33
+ };
34
+ export {};
@@ -0,0 +1,42 @@
1
+ import { HttpRouteDefinition, HttpRouteHandler, toSseFrame } from "@webiny/event-handler-core";
2
+ import { AdminAssistantUseCase } from "./abstractions.js";
3
+ import { parseChatBody } from "./parseChatBody.js";
4
+ const BAD_REQUEST_MESSAGE = "Provide either a non-empty `prompt` string or a `messages` array of model messages.";
5
+ async function* toSseFrames(events) {
6
+ for await (const event of events)yield toSseFrame(event);
7
+ }
8
+ class AdminAssistantStreamRouteImpl {
9
+ constructor(assistant){
10
+ this.assistant = assistant;
11
+ }
12
+ async handle(request, response) {
13
+ const parsed = parseChatBody(request.body);
14
+ if (!parsed) return response.status(400).json({
15
+ error: BAD_REQUEST_MESSAGE
16
+ });
17
+ const events = this.assistant.stream(parsed);
18
+ const frames = toSseFrames(events);
19
+ return response.sse(frames);
20
+ }
21
+ }
22
+ const AdminAssistantStreamRoute = HttpRouteHandler.createImplementation({
23
+ implementation: AdminAssistantStreamRouteImpl,
24
+ dependencies: [
25
+ AdminAssistantUseCase
26
+ ]
27
+ });
28
+ class AdminAssistantStreamRouteDefinitionImpl {
29
+ constructor(){
30
+ this.name = "admin-assistant-stream";
31
+ this.method = "POST";
32
+ this.path = "/stream/ai/admin-assistant";
33
+ this.handler = AdminAssistantStreamRoute;
34
+ }
35
+ }
36
+ const AdminAssistantStreamRouteDefinition = HttpRouteDefinition.createImplementation({
37
+ implementation: AdminAssistantStreamRouteDefinitionImpl,
38
+ dependencies: []
39
+ });
40
+ export { AdminAssistantStreamRoute, AdminAssistantStreamRouteDefinition };
41
+
42
+ //# sourceMappingURL=AdminAssistantStreamRoute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api/features/AdminAssistant/AdminAssistantStreamRoute.js","sources":["../../../../src/api/features/AdminAssistant/AdminAssistantStreamRoute.ts"],"sourcesContent":["import { HttpRouteDefinition, HttpRouteHandler, toSseFrame } from \"@webiny/event-handler-core\";\nimport type { IHttpRequest, IHttpResponseBuilder } from \"@webiny/event-handler-core\";\nimport { AdminAssistantUseCase } from \"./abstractions.js\";\nimport type { AdminAssistantEvent } from \"./events.js\";\nimport { parseChatBody } from \"./parseChatBody.js\";\n\nconst BAD_REQUEST_MESSAGE =\n \"Provide either a non-empty `prompt` string or a `messages` array of model messages.\";\n\n/**\n * Frame the feature's events as SSE records. The wire format comes from `event-handler-core`; which\n * events exist, and what they carry, belongs to the feature, so the mapping lives here.\n */\nasync function* toSseFrames(events: AsyncIterable<AdminAssistantEvent>): AsyncIterable<string> {\n for await (const event of events) {\n yield toSseFrame(event);\n }\n}\n\n/**\n * `POST /stream/ai/admin-assistant`, reported as it works rather than all at once.\n *\n * A separate route rather than a flag on the buffered one: the two have genuinely different response\n * contracts (one JSON object versus an event stream), so a client picks which it wants by the URL it\n * calls, and the buffered route stays available for callers that cannot read a stream.\n *\n * Failures after the first byte cannot become a status code, since the response has already committed\n * to 200, so the use case reports them as `error` events and the stream ends normally.\n */\nclass AdminAssistantStreamRouteImpl implements HttpRouteHandler.Interface {\n public constructor(private readonly assistant: AdminAssistantUseCase.Interface) {}\n\n public async handle(\n request: IHttpRequest,\n response: IHttpResponseBuilder\n ): Promise<IHttpResponseBuilder> {\n const parsed = parseChatBody(request.body);\n\n if (!parsed) {\n return response.status(400).json({ error: BAD_REQUEST_MESSAGE });\n }\n\n const events = this.assistant.stream(parsed);\n const frames = toSseFrames(events);\n\n return response.sse(frames);\n }\n}\n\nexport const AdminAssistantStreamRoute = HttpRouteHandler.createImplementation({\n implementation: AdminAssistantStreamRouteImpl,\n dependencies: [AdminAssistantUseCase]\n});\n\nclass AdminAssistantStreamRouteDefinitionImpl implements HttpRouteDefinition.Interface {\n readonly name = \"admin-assistant-stream\";\n readonly method = \"POST\";\n /*\n * Under `/stream/*` because that prefix is what reaches a transport able to stream. On AWS,\n * CloudFront routes `/stream/*` to the Lambda Function URL origin; everything else goes to API\n * Gateway, which buffers the whole response no matter how the route produced it. A path outside\n * this prefix still works, it just silently arrives all at once.\n */\n readonly path = \"/stream/ai/admin-assistant\";\n readonly handler = AdminAssistantStreamRoute;\n}\n\n/** What the router matches on. Zero dependencies, so building it costs nothing. */\nexport const AdminAssistantStreamRouteDefinition = HttpRouteDefinition.createImplementation({\n implementation: AdminAssistantStreamRouteDefinitionImpl,\n dependencies: []\n});\n"],"names":["BAD_REQUEST_MESSAGE","toSseFrames","events","event","toSseFrame","AdminAssistantStreamRouteImpl","assistant","request","response","parsed","parseChatBody","frames","AdminAssistantStreamRoute","HttpRouteHandler","AdminAssistantUseCase","AdminAssistantStreamRouteDefinitionImpl","AdminAssistantStreamRouteDefinition","HttpRouteDefinition"],"mappings":";;;AAMA,MAAMA,sBACF;AAMJ,gBAAgBC,YAAYC,MAA0C;IAClE,WAAW,MAAMC,SAASD,OACtB,MAAME,WAAWD;AAEzB;AAYA,MAAME;IACF,YAAoCC,SAA0C,CAAE;aAA5CA,SAAS,GAATA;IAA6C;IAEjF,MAAa,OACTC,OAAqB,EACrBC,QAA8B,EACD;QAC7B,MAAMC,SAASC,cAAcH,QAAQ,IAAI;QAEzC,IAAI,CAACE,QACD,OAAOD,SAAS,MAAM,CAAC,KAAK,IAAI,CAAC;YAAE,OAAOR;QAAoB;QAGlE,MAAME,SAAS,IAAI,CAAC,SAAS,CAAC,MAAM,CAACO;QACrC,MAAME,SAASV,YAAYC;QAE3B,OAAOM,SAAS,GAAG,CAACG;IACxB;AACJ;AAEO,MAAMC,4BAA4BC,iBAAiB,oBAAoB,CAAC;IAC3E,gBAAgBR;IAChB,cAAc;QAACS;KAAsB;AACzC;AAEA,MAAMC;;aACO,IAAI,GAAG;aACP,MAAM,GAAG;QAMjB,KACQ,IAAI,GAAG;aACP,OAAO,GAAGH;;AACvB;AAGO,MAAMI,sCAAsCC,oBAAoB,oBAAoB,CAAC;IACxF,gBAAgBF;IAChB,cAAc,EAAE;AACpB"}
@@ -0,0 +1,42 @@
1
+ import { Ai } from "@webiny/api-core/features/ai/index.js";
2
+ import { AiSdkToolDefinition } from "@webiny/api-core/features/ai/index.js";
3
+ import { AiSdkTools } from "@webiny/api-core/features/ai/index.js";
4
+ import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/index.js";
5
+ import { ResolveAiCapabilityUseCase } from "../../../api/features/Capabilities/index.js";
6
+ import { AdminAssistantConfig } from "./abstractions.js";
7
+ import { AdminAssistantUseCase as Abstraction } from "./abstractions.js";
8
+ import type { AdminAssistantParams } from "./abstractions.js";
9
+ import type { AdminAssistantEvent } from "./events.js";
10
+ /**
11
+ * Answers a question about the project by running an agent loop over the registered `AiSdkToolDefinition`s.
12
+ *
13
+ * Writes are gated. A tool that does not declare `readOnlyHint` is never executed on the model's word
14
+ * alone — the loop pauses and the pending call is returned for a human to approve. Everything runs
15
+ * under the caller's identity, so each tool is checked against that user's own permissions.
16
+ */
17
+ declare class AdminAssistantUseCaseImpl implements Abstraction.Interface {
18
+ private readonly ai;
19
+ private readonly aiSdkTools;
20
+ private readonly declarations;
21
+ private readonly identityContext;
22
+ private readonly config;
23
+ private readonly resolveCapability;
24
+ constructor(ai: Ai.Interface, aiSdkTools: AiSdkTools.Interface, declarations: AiSdkToolDefinition.Interface[], identityContext: IdentityContext.Interface, config: AdminAssistantConfig.Interface, resolveCapability: ResolveAiCapabilityUseCase.Interface);
25
+ stream(params: AdminAssistantParams): AsyncIterable<AdminAssistantEvent>;
26
+ /**
27
+ * Everything both entry points need: the identity check, which tools may run unattended, and the
28
+ * fully-formed model request. Shared so streaming and buffered runs cannot drift apart.
29
+ */
30
+ private prepare;
31
+ /**
32
+ * `result.text` is empty when the run ended on a tool call or an approval request, so fall back to
33
+ * the most recent step that produced prose.
34
+ */
35
+ private extractText;
36
+ private extractToolCalls;
37
+ private extractPendingApprovals;
38
+ }
39
+ export declare const AdminAssistantUseCase: typeof AdminAssistantUseCaseImpl & {
40
+ __abstraction: import("@webiny/di").Abstraction<import("./abstractions.js").IAdminAssistantUseCase>;
41
+ };
42
+ export {};
@@ -0,0 +1,170 @@
1
+ import { stepCountIs } from "ai";
2
+ import { Ai, AiSdkToolDefinition, AiSdkTools } from "@webiny/api-core/features/ai/index.js";
3
+ import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/index.js";
4
+ import { NotAuthorizedError } from "@webiny/api-core/features/security/shared/errors.js";
5
+ import { ResolveAiCapabilityUseCase, withAdditionalInstructions } from "../Capabilities/index.js";
6
+ import { AdminAssistantConfig, AdminAssistantUseCase } from "./abstractions.js";
7
+ import { ADMIN_ASSISTANT_CAPABILITY } from "./capability.js";
8
+ import { isReadOnly, toPendingApproval } from "./approvals.js";
9
+ const toMessage = (error)=>error instanceof Error ? error.message : String(error);
10
+ const toApprovalMessage = (decisions)=>({
11
+ role: "tool",
12
+ content: decisions.map((decision)=>{
13
+ const part = {
14
+ type: "tool-approval-response",
15
+ approvalId: decision.approvalId,
16
+ approved: decision.approved
17
+ };
18
+ if (decision.reason) part.reason = decision.reason;
19
+ return part;
20
+ })
21
+ });
22
+ class AdminAssistantUseCaseImpl {
23
+ constructor(ai, aiSdkTools, declarations, identityContext, config, resolveCapability){
24
+ this.ai = ai;
25
+ this.aiSdkTools = aiSdkTools;
26
+ this.declarations = declarations;
27
+ this.identityContext = identityContext;
28
+ this.config = config;
29
+ this.resolveCapability = resolveCapability;
30
+ }
31
+ async *stream(params) {
32
+ let prepared;
33
+ try {
34
+ prepared = await this.prepare(params);
35
+ } catch (error) {
36
+ yield {
37
+ type: "error",
38
+ message: toMessage(error)
39
+ };
40
+ return;
41
+ }
42
+ const { request, appended } = prepared;
43
+ const pending = [];
44
+ try {
45
+ const result = await this.ai.streamText(request);
46
+ for await (const part of result.fullStream){
47
+ if ("text-delta" === part.type && part.text) {
48
+ yield {
49
+ type: "text",
50
+ text: part.text
51
+ };
52
+ continue;
53
+ }
54
+ if ("tool-call" === part.type && part.toolName) {
55
+ yield {
56
+ type: "tool-call",
57
+ name: part.toolName
58
+ };
59
+ continue;
60
+ }
61
+ if ("tool-result" === part.type && part.toolName) {
62
+ yield {
63
+ type: "tool-result",
64
+ name: part.toolName
65
+ };
66
+ continue;
67
+ }
68
+ if ("tool-error" === part.type && part.toolName) {
69
+ yield {
70
+ type: "tool-error",
71
+ name: part.toolName,
72
+ message: toMessage(part.error)
73
+ };
74
+ continue;
75
+ }
76
+ if ("tool-approval-request" === part.type && part.approvalId && part.toolCall) {
77
+ pending.push(toPendingApproval(part.approvalId, part.toolCall.toolName, part.toolCall.input, this.declarations));
78
+ continue;
79
+ }
80
+ if ("error" === part.type) return void (yield {
81
+ type: "error",
82
+ message: toMessage(part.error)
83
+ });
84
+ }
85
+ if (pending.length > 0) yield {
86
+ type: "approval",
87
+ approvals: pending
88
+ };
89
+ yield {
90
+ type: "done",
91
+ messages: [
92
+ ...appended,
93
+ ...await result.responseMessages
94
+ ],
95
+ steps: (await result.steps).length
96
+ };
97
+ } catch (error) {
98
+ yield {
99
+ type: "error",
100
+ message: toMessage(error)
101
+ };
102
+ }
103
+ }
104
+ async prepare(params) {
105
+ if (this.identityContext.getIdentity().isAnonymous()) throw new NotAuthorizedError();
106
+ const tools = this.aiSdkTools.getToolSet();
107
+ const readOnlyNames = new Set(this.declarations.filter(isReadOnly).map((declaration)=>declaration.name));
108
+ const activeTools = Object.keys(tools);
109
+ const appended = [];
110
+ if (params.decisions.length > 0) appended.push(toApprovalMessage(params.decisions));
111
+ const messages = [
112
+ ...params.messages,
113
+ ...appended
114
+ ];
115
+ const resolution = await this.resolveCapability.execute(ADMIN_ASSISTANT_CAPABILITY);
116
+ if (resolution.isFail()) throw resolution.error;
117
+ const capability = resolution.value;
118
+ const request = {
119
+ model: capability.model,
120
+ connection: capability.connection,
121
+ system: withAdditionalInstructions(capability),
122
+ messages,
123
+ tools,
124
+ activeTools,
125
+ toolChoice: "auto",
126
+ toolApproval: ({ toolCall })=>readOnlyNames.has(toolCall.toolName) ? "not-applicable" : "user-approval",
127
+ stopWhen: stepCountIs(this.config.maxSteps)
128
+ };
129
+ return {
130
+ request,
131
+ appended
132
+ };
133
+ }
134
+ extractText(result) {
135
+ if (result.text) return result.text;
136
+ const lastWithText = result.steps.filter((step)=>step.text.length > 0).pop();
137
+ return lastWithText ? lastWithText.text : "";
138
+ }
139
+ extractToolCalls(result) {
140
+ return result.steps.flatMap((step)=>step.toolCalls.map((call)=>({
141
+ name: call.toolName,
142
+ input: call.input
143
+ })));
144
+ }
145
+ extractPendingApprovals(result) {
146
+ return result.steps.flatMap((step)=>step.content.filter((part)=>"tool-approval-request" === part.type).map((part)=>{
147
+ const request = part;
148
+ return toPendingApproval(request.approvalId, request.toolCall.toolName, request.toolCall.input, this.declarations);
149
+ }));
150
+ }
151
+ }
152
+ const AdminAssistantUseCase_AdminAssistantUseCase = AdminAssistantUseCase.createImplementation({
153
+ implementation: AdminAssistantUseCaseImpl,
154
+ dependencies: [
155
+ Ai,
156
+ AiSdkTools,
157
+ [
158
+ AiSdkToolDefinition,
159
+ {
160
+ multiple: true
161
+ }
162
+ ],
163
+ IdentityContext,
164
+ AdminAssistantConfig,
165
+ ResolveAiCapabilityUseCase
166
+ ]
167
+ });
168
+ export { AdminAssistantUseCase_AdminAssistantUseCase as AdminAssistantUseCase };
169
+
170
+ //# sourceMappingURL=AdminAssistantUseCase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api/features/AdminAssistant/AdminAssistantUseCase.js","sources":["../../../../src/api/features/AdminAssistant/AdminAssistantUseCase.ts"],"sourcesContent":["import { stepCountIs } from \"ai\";\nimport type { ModelMessage } from \"ai\";\nimport { Ai } from \"@webiny/api-core/features/ai/index.js\";\nimport { AiSdkToolDefinition } from \"@webiny/api-core/features/ai/index.js\";\nimport { AiSdkTools } from \"@webiny/api-core/features/ai/index.js\";\nimport { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/index.js\";\nimport { NotAuthorizedError } from \"@webiny/api-core/features/security/shared/errors.js\";\nimport {\n ResolveAiCapabilityUseCase,\n withAdditionalInstructions\n} from \"~/api/features/Capabilities/index.js\";\nimport { AdminAssistantConfig } from \"./abstractions.js\";\nimport { ADMIN_ASSISTANT_CAPABILITY } from \"./capability.js\";\nimport { AdminAssistantUseCase as Abstraction } from \"./abstractions.js\";\nimport type { AdminAssistantParams } from \"./abstractions.js\";\nimport { isReadOnly } from \"./approvals.js\";\nimport { toPendingApproval } from \"./approvals.js\";\nimport type { ApprovalDecision } from \"./approvals.js\";\nimport type { PendingApproval } from \"./approvals.js\";\nimport type { AdminAssistantEvent } from \"./events.js\";\n\n/** The subset of the AI SDK's stream parts this use case reacts to. */\ninterface StreamPart {\n type: string;\n text?: string;\n toolName?: string;\n approvalId?: string;\n toolCall?: {\n toolName: string;\n input: unknown;\n };\n error?: unknown;\n}\n\nconst toMessage = (error: unknown): string => {\n return error instanceof Error ? error.message : String(error);\n};\n\ninterface ApprovalRequestPart {\n approvalId: string;\n toolCall: {\n toolName: string;\n input: unknown;\n };\n}\n\n/**\n * Turns the caller's approve/reject decisions into the tool message the SDK expects. Sent as its own\n * message so it lands after the assistant message that requested it.\n */\nconst toApprovalMessage = (decisions: ApprovalDecision[]): ModelMessage => {\n return {\n role: \"tool\",\n content: decisions.map(decision => {\n const part: {\n type: \"tool-approval-response\";\n approvalId: string;\n approved: boolean;\n reason?: string;\n } = {\n type: \"tool-approval-response\",\n approvalId: decision.approvalId,\n approved: decision.approved\n };\n\n if (decision.reason) {\n part.reason = decision.reason;\n }\n\n return part;\n })\n };\n};\n\n/**\n * Answers a question about the project by running an agent loop over the registered `AiSdkToolDefinition`s.\n *\n * Writes are gated. A tool that does not declare `readOnlyHint` is never executed on the model's word\n * alone — the loop pauses and the pending call is returned for a human to approve. Everything runs\n * under the caller's identity, so each tool is checked against that user's own permissions.\n */\nclass AdminAssistantUseCaseImpl implements Abstraction.Interface {\n constructor(\n private readonly ai: Ai.Interface,\n private readonly aiSdkTools: AiSdkTools.Interface,\n private readonly declarations: AiSdkToolDefinition.Interface[],\n private readonly identityContext: IdentityContext.Interface,\n private readonly config: AdminAssistantConfig.Interface,\n private readonly resolveCapability: ResolveAiCapabilityUseCase.Interface\n ) {}\n\n async *stream(params: AdminAssistantParams): AsyncIterable<AdminAssistantEvent> {\n let prepared;\n\n /*\n * An auth failure has to arrive as an event, not a thrown error: by the time a transport is\n * iterating this it has already committed to a 200 and a stream, so there is no status code\n * left to change.\n */\n try {\n prepared = await this.prepare(params);\n } catch (error) {\n yield { type: \"error\", message: toMessage(error) };\n return;\n }\n\n const { request, appended } = prepared;\n const pending: PendingApproval[] = [];\n\n try {\n const result = await this.ai.streamText(request);\n\n for await (const part of result.fullStream as AsyncIterable<StreamPart>) {\n if (part.type === \"text-delta\" && part.text) {\n yield { type: \"text\", text: part.text };\n continue;\n }\n\n if (part.type === \"tool-call\" && part.toolName) {\n yield { type: \"tool-call\", name: part.toolName };\n continue;\n }\n\n if (part.type === \"tool-result\" && part.toolName) {\n yield { type: \"tool-result\", name: part.toolName };\n continue;\n }\n\n /*\n * A tool threw. Deliberately not terminal, unlike the stream-level `error` below:\n * the SDK hands the message to the model, which typically fixes its arguments and\n * tries again, so ending the run here would abort a recoverable turn. Every tool\n * reports failure this way, so an unhandled `tool-error` leaves the call with no\n * outcome at all.\n */\n if (part.type === \"tool-error\" && part.toolName) {\n yield {\n type: \"tool-error\",\n name: part.toolName,\n message: toMessage(part.error)\n };\n continue;\n }\n\n if (part.type === \"tool-approval-request\" && part.approvalId && part.toolCall) {\n pending.push(\n toPendingApproval(\n part.approvalId,\n part.toolCall.toolName,\n part.toolCall.input,\n this.declarations\n )\n );\n continue;\n }\n\n if (part.type === \"error\") {\n yield { type: \"error\", message: toMessage(part.error) };\n return;\n }\n }\n\n if (pending.length > 0) {\n yield { type: \"approval\", approvals: pending };\n }\n\n /*\n * `responseMessages`, not `response.messages`: the former is the ACCUMULATED history of\n * every step, the latter only the final step's. Resuming after an approval needs the step\n * that carried the approval request, so the narrower one silently broke every write —\n * the client replayed a single message, the SDK could not match the approvalId, and the\n * model simply proposed the change again.\n *\n * Awaited only after the stream drains: these settle when the run finishes, so reading\n * them earlier would block the loop above and defeat the point of streaming.\n */\n yield {\n type: \"done\",\n messages: [...appended, ...(await result.responseMessages)],\n steps: (await result.steps).length\n };\n } catch (error) {\n yield { type: \"error\", message: toMessage(error) };\n }\n }\n\n /**\n * Everything both entry points need: the identity check, which tools may run unattended, and the\n * fully-formed model request. Shared so streaming and buffered runs cannot drift apart.\n */\n private async prepare(params: AdminAssistantParams): Promise<{\n request: Ai.GenerateTextParams;\n appended: ModelMessage[];\n }> {\n if (this.identityContext.getIdentity().isAnonymous()) {\n throw new NotAuthorizedError();\n }\n\n const tools = this.aiSdkTools.getToolSet();\n const readOnlyNames = new Set(\n this.declarations.filter(isReadOnly).map(declaration => declaration.name)\n );\n\n /*\n * Every tool is offered. The controls are the caller's own permissions — each tool runs through\n * the same use cases as the admin UI — and the approval pause, which stops a mutating call\n * until a human has seen its exact arguments.\n */\n const activeTools = Object.keys(tools);\n\n /*\n * Anything added here has to come back to the caller. The client replays the history on the\n * next turn, and an approval response that never reached it would leave a `tool_result` with\n * no preceding `tool_use` — which the provider rejects outright.\n */\n const appended: ModelMessage[] = [];\n if (params.decisions.length > 0) {\n appended.push(toApprovalMessage(params.decisions));\n }\n\n const messages = [...params.messages, ...appended];\n\n const resolution = await this.resolveCapability.execute(ADMIN_ASSISTANT_CAPABILITY);\n\n /*\n * Thrown rather than swallowed. Every message the resolver produces names the setting to\n * fix, and `stream` turns a throw into an `error` event, so the editor reads \"pick a model\n * under Settings → AI Power-Ups → Model roles\" instead of watching the assistant fail.\n */\n if (resolution.isFail()) {\n throw resolution.error;\n }\n\n const capability = resolution.value;\n\n const request: Ai.GenerateTextParams = {\n model: capability.model,\n connection: capability.connection,\n system: withAdditionalInstructions(capability),\n messages,\n tools,\n activeTools,\n toolChoice: \"auto\",\n toolApproval: ({ toolCall }: { toolCall: { toolName: string } }) => {\n return readOnlyNames.has(toolCall.toolName) ? \"not-applicable\" : \"user-approval\";\n },\n stopWhen: stepCountIs(this.config.maxSteps)\n };\n\n return { request, appended };\n }\n\n /**\n * `result.text` is empty when the run ended on a tool call or an approval request, so fall back to\n * the most recent step that produced prose.\n */\n private extractText(result: { text: string; steps: { text: string }[] }): string {\n if (result.text) {\n return result.text;\n }\n\n const lastWithText = result.steps.filter(step => step.text.length > 0).pop();\n\n return lastWithText ? lastWithText.text : \"\";\n }\n\n private extractToolCalls(result: {\n steps: { toolCalls: { toolName: string; input: unknown }[] }[];\n }): { name: string; input: unknown }[] {\n return result.steps.flatMap(step => {\n return step.toolCalls.map(call => ({ name: call.toolName, input: call.input }));\n });\n }\n\n private extractPendingApprovals(result: {\n steps: { content: unknown[] }[];\n }): PendingApproval[] {\n return result.steps.flatMap(step => {\n return step.content\n .filter(part => (part as { type: string }).type === \"tool-approval-request\")\n .map(part => {\n const request = part as unknown as ApprovalRequestPart;\n\n return toPendingApproval(\n request.approvalId,\n request.toolCall.toolName,\n request.toolCall.input,\n this.declarations\n );\n });\n });\n }\n}\n\nexport const AdminAssistantUseCase = Abstraction.createImplementation({\n implementation: AdminAssistantUseCaseImpl,\n dependencies: [\n Ai,\n AiSdkTools,\n [AiSdkToolDefinition, { multiple: true }],\n IdentityContext,\n AdminAssistantConfig,\n ResolveAiCapabilityUseCase\n ]\n});\n"],"names":["toMessage","error","Error","String","toApprovalMessage","decisions","decision","part","AdminAssistantUseCaseImpl","ai","aiSdkTools","declarations","identityContext","config","resolveCapability","params","prepared","request","appended","pending","result","toPendingApproval","NotAuthorizedError","tools","readOnlyNames","Set","isReadOnly","declaration","activeTools","Object","messages","resolution","ADMIN_ASSISTANT_CAPABILITY","capability","withAdditionalInstructions","toolCall","stepCountIs","lastWithText","step","call","AdminAssistantUseCase","Abstraction","Ai","AiSdkTools","AiSdkToolDefinition","IdentityContext","AdminAssistantConfig","ResolveAiCapabilityUseCase"],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { ModelMessage } from "ai";
2
+ import type { ApprovalDecision } from "./approvals.js";
3
+ import type { AdminAssistantEvent } from "./events.js";
4
+ export interface IAdminAssistantConfig {
5
+ /**
6
+ * Upper bound on agent loop steps. Each tool call plus the final answer is a step, so a
7
+ * three-tool question (list models, describe, query) needs at least four.
8
+ */
9
+ readonly maxSteps: number;
10
+ }
11
+ /** Runtime limits for the assistant. The model comes from its capability. */
12
+ export declare const AdminAssistantConfig: import("@webiny/di").Abstraction<IAdminAssistantConfig>;
13
+ export declare namespace AdminAssistantConfig {
14
+ type Interface = IAdminAssistantConfig;
15
+ }
16
+ export interface AdminAssistantParams {
17
+ /** Conversation so far. Replayed verbatim, since approval requests live only in these messages. */
18
+ messages: ModelMessage[];
19
+ /** Approve or reject tool calls a previous run paused on. */
20
+ decisions: ApprovalDecision[];
21
+ }
22
+ export interface IAdminAssistantUseCase {
23
+ /**
24
+ * Run, and emit progress as it happens.
25
+ *
26
+ * Streaming only. A buffered `execute()` existed alongside this and nothing ever called it: a
27
+ * multi-tool question takes tens of seconds, so every caller wants the answer as it arrives, and
28
+ * the approval pause is worth showing the moment it appears rather than after everything
29
+ * settles. Anything that genuinely wants the whole result can collect the events.
30
+ */
31
+ stream(params: AdminAssistantParams): AsyncIterable<AdminAssistantEvent>;
32
+ }
33
+ /** Answer a question about the project using the registered AI tools, gating writes on approval. */
34
+ export declare const AdminAssistantUseCase: import("@webiny/di").Abstraction<IAdminAssistantUseCase>;
35
+ export declare namespace AdminAssistantUseCase {
36
+ type Interface = IAdminAssistantUseCase;
37
+ type Params = AdminAssistantParams;
38
+ }
@@ -0,0 +1,6 @@
1
+ import { createAbstraction } from "@webiny/feature/api";
2
+ const AdminAssistantConfig = createAbstraction("AdminAssistantConfig");
3
+ const AdminAssistantUseCase = createAbstraction("AdminAssistantUseCase");
4
+ export { AdminAssistantConfig, AdminAssistantUseCase };
5
+
6
+ //# sourceMappingURL=abstractions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api/features/AdminAssistant/abstractions.js","sources":["../../../../src/api/features/AdminAssistant/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/api\";\nimport type { ModelMessage } from \"ai\";\nimport type { ApprovalDecision } from \"./approvals.js\";\nimport type { AdminAssistantEvent } from \"./events.js\";\n\nexport interface IAdminAssistantConfig {\n /**\n * Upper bound on agent loop steps. Each tool call plus the final answer is a step, so a\n * three-tool question (list models, describe, query) needs at least four.\n */\n readonly maxSteps: number;\n}\n\n/** Runtime limits for the assistant. The model comes from its capability. */\nexport const AdminAssistantConfig =\n createAbstraction<IAdminAssistantConfig>(\"AdminAssistantConfig\");\n\nexport namespace AdminAssistantConfig {\n export type Interface = IAdminAssistantConfig;\n}\n\nexport interface AdminAssistantParams {\n /** Conversation so far. Replayed verbatim, since approval requests live only in these messages. */\n messages: ModelMessage[];\n /** Approve or reject tool calls a previous run paused on. */\n decisions: ApprovalDecision[];\n}\n\nexport interface IAdminAssistantUseCase {\n /**\n * Run, and emit progress as it happens.\n *\n * Streaming only. A buffered `execute()` existed alongside this and nothing ever called it: a\n * multi-tool question takes tens of seconds, so every caller wants the answer as it arrives, and\n * the approval pause is worth showing the moment it appears rather than after everything\n * settles. Anything that genuinely wants the whole result can collect the events.\n */\n stream(params: AdminAssistantParams): AsyncIterable<AdminAssistantEvent>;\n}\n\n/** Answer a question about the project using the registered AI tools, gating writes on approval. */\nexport const AdminAssistantUseCase =\n createAbstraction<IAdminAssistantUseCase>(\"AdminAssistantUseCase\");\n\nexport namespace AdminAssistantUseCase {\n export type Interface = IAdminAssistantUseCase;\n export type Params = AdminAssistantParams;\n}\n"],"names":["AdminAssistantConfig","createAbstraction","AdminAssistantUseCase"],"mappings":";AAcO,MAAMA,uBACTC,kBAAyC;AA0BtC,MAAMC,wBACTD,kBAA0C"}
@@ -0,0 +1,29 @@
1
+ import { AiSdkToolDefinition } from "@webiny/api-core/features/ai/index.js";
2
+ /**
3
+ * A tool call the assistant wants to make but has not made, because it mutates something.
4
+ * Returned to the client so a human can approve or reject it.
5
+ */
6
+ export interface PendingApproval {
7
+ approvalId: string;
8
+ toolName: string;
9
+ /** Human-readable tool name where the tool supplied one. */
10
+ title?: string;
11
+ input: unknown;
12
+ /** True when the tool declared `destructiveHint` — the UI should say so louder. */
13
+ destructive: boolean;
14
+ }
15
+ export interface ApprovalDecision {
16
+ approvalId: string;
17
+ approved: boolean;
18
+ reason?: string;
19
+ }
20
+ /**
21
+ * A tool runs unattended only if it says, in its own declaration, that it does not change anything.
22
+ *
23
+ * The default is deliberately the safe one: a tool with no annotations requires approval. Tools are
24
+ * registered by extensions as well as by Webiny, so an author who forgets to annotate gets a confirm
25
+ * prompt rather than silent write access.
26
+ */
27
+ export declare const isReadOnly: (tool: AiSdkToolDefinition.Interface) => boolean;
28
+ export declare const toPendingApproval: (approvalId: string, toolName: string, input: unknown, tools: AiSdkToolDefinition.Interface[]) => PendingApproval;
29
+ export declare const parseDecisions: (value: unknown) => ApprovalDecision[];
@@ -0,0 +1,30 @@
1
+ const isReadOnly = (tool)=>tool.annotations?.readOnlyHint === true;
2
+ const toPendingApproval = (approvalId, toolName, input, tools)=>{
3
+ const tool = tools.find((candidate)=>candidate.name === toolName);
4
+ return {
5
+ approvalId,
6
+ toolName,
7
+ title: tool?.title,
8
+ input,
9
+ destructive: tool?.annotations?.destructiveHint === true
10
+ };
11
+ };
12
+ const parseDecisions = (value)=>{
13
+ if (!Array.isArray(value)) return [];
14
+ return value.flatMap((entry)=>{
15
+ if (!entry || "object" != typeof entry) return [];
16
+ const { approvalId, approved, reason } = entry;
17
+ if ("string" != typeof approvalId || "boolean" != typeof approved) return [];
18
+ const decision = {
19
+ approvalId,
20
+ approved
21
+ };
22
+ if ("string" == typeof reason) decision.reason = reason;
23
+ return [
24
+ decision
25
+ ];
26
+ });
27
+ };
28
+ export { isReadOnly, parseDecisions, toPendingApproval };
29
+
30
+ //# sourceMappingURL=approvals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api/features/AdminAssistant/approvals.js","sources":["../../../../src/api/features/AdminAssistant/approvals.ts"],"sourcesContent":["import { AiSdkToolDefinition } from \"@webiny/api-core/features/ai/index.js\";\n\n/**\n * A tool call the assistant wants to make but has not made, because it mutates something.\n * Returned to the client so a human can approve or reject it.\n */\nexport interface PendingApproval {\n approvalId: string;\n toolName: string;\n /** Human-readable tool name where the tool supplied one. */\n title?: string;\n input: unknown;\n /** True when the tool declared `destructiveHint` — the UI should say so louder. */\n destructive: boolean;\n}\n\nexport interface ApprovalDecision {\n approvalId: string;\n approved: boolean;\n reason?: string;\n}\n\n/**\n * A tool runs unattended only if it says, in its own declaration, that it does not change anything.\n *\n * The default is deliberately the safe one: a tool with no annotations requires approval. Tools are\n * registered by extensions as well as by Webiny, so an author who forgets to annotate gets a confirm\n * prompt rather than silent write access.\n */\nexport const isReadOnly = (tool: AiSdkToolDefinition.Interface): boolean =>\n tool.annotations?.readOnlyHint === true;\n\nexport const toPendingApproval = (\n approvalId: string,\n toolName: string,\n input: unknown,\n tools: AiSdkToolDefinition.Interface[]\n): PendingApproval => {\n const tool = tools.find(candidate => candidate.name === toolName);\n\n return {\n approvalId,\n toolName,\n title: tool?.title,\n input,\n destructive: tool?.annotations?.destructiveHint === true\n };\n};\n\nexport const parseDecisions = (value: unknown): ApprovalDecision[] => {\n if (!Array.isArray(value)) {\n return [];\n }\n\n return value.flatMap(entry => {\n if (!entry || typeof entry !== \"object\") {\n return [];\n }\n const { approvalId, approved, reason } = entry as Record<string, unknown>;\n if (typeof approvalId !== \"string\" || typeof approved !== \"boolean\") {\n return [];\n }\n const decision: ApprovalDecision = { approvalId, approved };\n\n if (typeof reason === \"string\") {\n decision.reason = reason;\n }\n\n return [decision];\n });\n};\n"],"names":["isReadOnly","tool","toPendingApproval","approvalId","toolName","input","tools","candidate","parseDecisions","value","Array","entry","approved","reason","decision"],"mappings":"AA6BO,MAAMA,aAAa,CAACC,OACvBA,KAAK,WAAW,EAAE,iBAAiB;AAEhC,MAAMC,oBAAoB,CAC7BC,YACAC,UACAC,OACAC;IAEA,MAAML,OAAOK,MAAM,IAAI,CAACC,CAAAA,YAAaA,UAAU,IAAI,KAAKH;IAExD,OAAO;QACHD;QACAC;QACA,OAAOH,MAAM;QACbI;QACA,aAAaJ,MAAM,aAAa,oBAAoB;IACxD;AACJ;AAEO,MAAMO,iBAAiB,CAACC;IAC3B,IAAI,CAACC,MAAM,OAAO,CAACD,QACf,OAAO,EAAE;IAGb,OAAOA,MAAM,OAAO,CAACE,CAAAA;QACjB,IAAI,CAACA,SAAS,AAAiB,YAAjB,OAAOA,OACjB,OAAO,EAAE;QAEb,MAAM,EAAER,UAAU,EAAES,QAAQ,EAAEC,MAAM,EAAE,GAAGF;QACzC,IAAI,AAAsB,YAAtB,OAAOR,cAA2B,AAAoB,aAApB,OAAOS,UACzC,OAAO,EAAE;QAEb,MAAME,WAA6B;YAAEX;YAAYS;QAAS;QAE1D,IAAI,AAAkB,YAAlB,OAAOC,QACPC,SAAS,MAAM,GAAGD;QAGtB,OAAO;YAACC;SAAS;IACrB;AACJ"}
@@ -0,0 +1,31 @@
1
+ import { AiCapability } from "../../../api/features/Capabilities/index.js";
2
+ export declare const ADMIN_ASSISTANT_CAPABILITY = "admin.assistant";
3
+ /**
4
+ * The assistant behind the admin command palette.
5
+ *
6
+ * `admin.assistant` matches the WCP licence option and the `aiPowerups.adminAssistant` flag, so the
7
+ * feature has one name everywhere. It is also the name that survives: every other id says what the
8
+ * feature does (`fm.imageEnrichment`, `cms.generateEntry`), and this one deliberately does not do
9
+ * one thing. Today it reads and changes content, and the direction is for it to build things
10
+ * too, like a field renderer or a menu change. The id is the persisted settings key, so a later rename
11
+ * orphans a project's overrides.
12
+ *
13
+ * `guidance` is the prompt this feature ships, imported rather than restated so the two cannot
14
+ * drift. Unlike most capabilities this one is safe to append to freely: its output is prose for a
15
+ * human, not a shape the surrounding code parses. House rules ("our product is spelled like this",
16
+ * "never mention internal model ids") belong here.
17
+ *
18
+ * `standard` rather than `fast`: the assistant chains tool calls and has to reason about which model
19
+ * to describe before it can query anything, which is where small models fall down.
20
+ */
21
+ declare class AdminAssistantCapabilityImpl implements AiCapability.Interface {
22
+ readonly id = "admin.assistant";
23
+ readonly label = "Admin assistant";
24
+ readonly description = "The assistant in the command palette. Answers questions about this project and proposes changes for approval, under the permissions of whoever is asking. The most open-ended capability here: it plans across several tool calls, so it gains the most from a strong model.";
25
+ readonly defaultRole: "standard";
26
+ readonly guidance = "You are the Webiny admin assistant. You help editors and developers find, understand and change the content in their Webiny project.\n\nYou have tools available. Use them \u2014 never answer a question about this project's content, models, or files from memory or assumption.\n\nHow to work:\n- Content model IDs and field IDs are specific to this project. Always discover them with listContentModels, then describeContentModel, before querying.\n- Build filters with the field IDs describeContentModel returned. Do not guess field names.\n- If a tool returns an error, read it and correct your call. A \"not allowed\" error means the user lacks permission \u2014 say so plainly rather than retrying.\n- If a query returns nothing, say so. Do not present an empty result as if it were data.\n\nChanging things:\n- Tools that change something are not executed until the user approves them. Propose the change by calling the tool; the user sees exactly what you asked for and confirms it.\n- Read first, then propose. Look up the ids you need (teams, folders, entries) rather than guessing them, because the user is approving the arguments you supply.\n- Propose one coherent change at a time. Do not bundle unrelated edits into a single step.\n- If an approval is denied, do not retry the same call. Acknowledge it and stop.\n\nHow to answer:\n- Be brief. These answers appear in a command palette, not a chat window.\n- Lead with the answer. No preamble, no restating the question.\n- When you list entries, give the few fields that matter, not every field you received.\n- State counts precisely (\"3 products are on sale\"), never vaguely.";
27
+ }
28
+ export declare const AdminAssistantCapability: typeof AdminAssistantCapabilityImpl & {
29
+ __abstraction: import("@webiny/di").Abstraction<import("~/api/features/Capabilities/index.js").IAiCapability>;
30
+ };
31
+ export {};
@@ -0,0 +1,19 @@
1
+ import { AiCapability } from "../Capabilities/index.js";
2
+ import { SYSTEM_PROMPT } from "./systemPrompt.js";
3
+ const ADMIN_ASSISTANT_CAPABILITY = "admin.assistant";
4
+ class AdminAssistantCapabilityImpl {
5
+ constructor(){
6
+ this.id = ADMIN_ASSISTANT_CAPABILITY;
7
+ this.label = "Admin assistant";
8
+ this.description = "The assistant in the command palette. Answers questions about this project and proposes changes for approval, under the permissions of whoever is asking. The most open-ended capability here: it plans across several tool calls, so it gains the most from a strong model.";
9
+ this.defaultRole = "standard";
10
+ this.guidance = SYSTEM_PROMPT;
11
+ }
12
+ }
13
+ const AdminAssistantCapability = AiCapability.createImplementation({
14
+ implementation: AdminAssistantCapabilityImpl,
15
+ dependencies: []
16
+ });
17
+ export { ADMIN_ASSISTANT_CAPABILITY, AdminAssistantCapability };
18
+
19
+ //# sourceMappingURL=capability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api/features/AdminAssistant/capability.js","sources":["../../../../src/api/features/AdminAssistant/capability.ts"],"sourcesContent":["import { AiCapability } from \"~/api/features/Capabilities/index.js\";\nimport { SYSTEM_PROMPT } from \"./systemPrompt.js\";\n\nexport const ADMIN_ASSISTANT_CAPABILITY = \"admin.assistant\";\n\n/**\n * The assistant behind the admin command palette.\n *\n * `admin.assistant` matches the WCP licence option and the `aiPowerups.adminAssistant` flag, so the\n * feature has one name everywhere. It is also the name that survives: every other id says what the\n * feature does (`fm.imageEnrichment`, `cms.generateEntry`), and this one deliberately does not do\n * one thing. Today it reads and changes content, and the direction is for it to build things\n * too, like a field renderer or a menu change. The id is the persisted settings key, so a later rename\n * orphans a project's overrides.\n *\n * `guidance` is the prompt this feature ships, imported rather than restated so the two cannot\n * drift. Unlike most capabilities this one is safe to append to freely: its output is prose for a\n * human, not a shape the surrounding code parses. House rules (\"our product is spelled like this\",\n * \"never mention internal model ids\") belong here.\n *\n * `standard` rather than `fast`: the assistant chains tool calls and has to reason about which model\n * to describe before it can query anything, which is where small models fall down.\n */\nclass AdminAssistantCapabilityImpl implements AiCapability.Interface {\n readonly id = ADMIN_ASSISTANT_CAPABILITY;\n readonly label = \"Admin assistant\";\n readonly description =\n \"The assistant in the command palette. Answers questions about this project and proposes changes for approval, under the permissions of whoever is asking. The most open-ended capability here: it plans across several tool calls, so it gains the most from a strong model.\";\n readonly defaultRole = \"standard\" as const;\n readonly guidance = SYSTEM_PROMPT;\n}\n\nexport const AdminAssistantCapability = AiCapability.createImplementation({\n implementation: AdminAssistantCapabilityImpl,\n dependencies: []\n});\n"],"names":["ADMIN_ASSISTANT_CAPABILITY","AdminAssistantCapabilityImpl","SYSTEM_PROMPT","AdminAssistantCapability","AiCapability"],"mappings":";;AAGO,MAAMA,6BAA6B;AAoB1C,MAAMC;;aACO,EAAE,GAAGD;aACL,KAAK,GAAG;aACR,WAAW,GAChB;aACK,WAAW,GAAG;aACd,QAAQ,GAAGE;;AACxB;AAEO,MAAMC,2BAA2BC,aAAa,oBAAoB,CAAC;IACtE,gBAAgBH;IAChB,cAAc,EAAE;AACpB"}