@ecsplico/editor 3.6.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (593) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/dist/adapters/direct-ai.d.ts +4 -4
  3. package/dist/adapters/direct-ai.js +2 -2
  4. package/dist/adapters/direct-ai.js.map +1 -1
  5. package/dist/adapters/document-state.d.ts +1 -1
  6. package/dist/adapters/document-state.js.map +1 -1
  7. package/dist/adapters/forge.d.ts +2 -2
  8. package/dist/adapters/forge.js.map +1 -1
  9. package/dist/adapters/nitro.d.ts +11 -3
  10. package/dist/adapters/nitro.js +3 -1
  11. package/dist/adapters/nitro.js.map +1 -1
  12. package/dist/adapters/shared.d.ts +6 -6
  13. package/dist/adapters/shared.js.map +1 -1
  14. package/dist/code/CodeSurface.vue.d.ts +3 -3
  15. package/dist/config/index.d.ts +14 -14
  16. package/dist/config/index.js +8 -8
  17. package/dist/config/index.js.map +1 -1
  18. package/dist/core/backend-types.d.ts +3 -3
  19. package/dist/core/backend-types.js.map +1 -1
  20. package/dist/core/backend.d.ts +4 -4
  21. package/dist/core/backend.js.map +1 -1
  22. package/dist/core/block-convert.d.ts +1 -1
  23. package/dist/core/block-convert.js +5 -5
  24. package/dist/core/block-convert.js.map +1 -1
  25. package/dist/core/block-transfer.d.ts +8 -4
  26. package/dist/core/block-transfer.js +23 -14
  27. package/dist/core/block-transfer.js.map +1 -1
  28. package/dist/core/capabilities.d.ts +113 -0
  29. package/dist/core/capabilities.js +155 -0
  30. package/dist/core/capabilities.js.map +1 -0
  31. package/dist/core/command-types.d.ts +1 -1
  32. package/dist/core/context.js.map +1 -1
  33. package/dist/core/convert.d.ts +5 -5
  34. package/dist/core/convert.js +5 -5
  35. package/dist/core/convert.js.map +1 -1
  36. package/dist/core/core-feature.js +1 -1
  37. package/dist/core/define-editor.d.ts +2 -2
  38. package/dist/core/define-editor.js +34 -6
  39. package/dist/core/define-editor.js.map +1 -1
  40. package/dist/core/derivation.d.ts +119 -0
  41. package/dist/core/derivation.js +187 -0
  42. package/dist/core/derivation.js.map +1 -0
  43. package/dist/core/derive.d.ts +61 -0
  44. package/dist/core/derive.js +69 -0
  45. package/dist/core/derive.js.map +1 -0
  46. package/dist/core/extension-points.d.ts +16 -0
  47. package/dist/core/feature-context.d.ts +5 -1
  48. package/dist/core/feature-context.js +10 -3
  49. package/dist/core/feature-context.js.map +1 -1
  50. package/dist/core/feature.d.ts +41 -19
  51. package/dist/core/feature.js.map +1 -1
  52. package/dist/core/fences.js +1 -1
  53. package/dist/core/fences.js.map +1 -1
  54. package/dist/core/index.d.ts +6 -2
  55. package/dist/core/index.js +5 -1
  56. package/dist/core/pipeline.d.ts +14 -5
  57. package/dist/core/pipeline.js +19 -7
  58. package/dist/core/pipeline.js.map +1 -1
  59. package/dist/core/properties.d.ts +22 -0
  60. package/dist/core/properties.js +17 -0
  61. package/dist/core/properties.js.map +1 -0
  62. package/dist/core/schema/block-ids.js +5 -5
  63. package/dist/core/schema/block-ids.js.map +1 -1
  64. package/dist/core/schema/index.d.ts +2 -1
  65. package/dist/core/schema/index.js +2 -1
  66. package/dist/core/schema/index.js.map +1 -1
  67. package/dist/core/schema/opaque-fence.d.ts +4 -4
  68. package/dist/core/schema/opaque-fence.js +7 -7
  69. package/dist/core/schema/opaque-fence.js.map +1 -1
  70. package/dist/core/schema/persisted-names.d.ts +58 -0
  71. package/dist/core/schema/persisted-names.js +96 -0
  72. package/dist/core/schema/persisted-names.js.map +1 -0
  73. package/dist/core/toolbar-items.js +1 -1
  74. package/dist/core/toolbar-items.js.map +1 -1
  75. package/dist/core/util.js +5 -1
  76. package/dist/core/util.js.map +1 -1
  77. package/dist/document/DocumentSurface.vue.d.ts +3 -3
  78. package/dist/features/ai/agent-ops.js +1 -1
  79. package/dist/features/ai/ai-review.js +1 -1
  80. package/dist/features/ai/assistant.d.ts +4 -4
  81. package/dist/features/ai/assistant.js +1 -1
  82. package/dist/features/ai/assistant.js.map +1 -1
  83. package/dist/features/ai/components/AiSelectionMenu.js +1 -1
  84. package/dist/features/ai/components/AiSelectionMenu.js.map +1 -1
  85. package/dist/features/ai/components/ModelQuickSwitch.js +7 -7
  86. package/dist/features/ai/components/ModelQuickSwitch.js.map +1 -1
  87. package/dist/features/ai/components/ModelQuickSwitch.vue.d.ts +4 -4
  88. package/dist/features/ai/components/SettingsAiTab.js +8 -8
  89. package/dist/features/ai/components/SettingsAiTab.js.map +1 -1
  90. package/dist/features/ai/components/SettingsModelProfiles.js +1 -1
  91. package/dist/features/ai/components/SettingsModelProfiles.js.map +1 -1
  92. package/dist/features/ai/document-chat-model.d.ts +2 -2
  93. package/dist/features/ai/document-chat-model.js +5 -5
  94. package/dist/features/ai/document-chat-model.js.map +1 -1
  95. package/dist/features/ai/document-chat.js +2 -2
  96. package/dist/features/ai/document-chat.js.map +1 -1
  97. package/dist/features/ai/feature.d.ts +2 -2
  98. package/dist/features/ai/feature.js +2 -2
  99. package/dist/features/ai/feature.js.map +1 -1
  100. package/dist/features/ai/ghost-autocomplete.d.ts +4 -4
  101. package/dist/features/ai/ghost-autocomplete.js +1 -1
  102. package/dist/features/ai/ghost-autocomplete.js.map +1 -1
  103. package/dist/features/ai/index.d.ts +3 -3
  104. package/dist/features/ai/index.js +2 -2
  105. package/dist/features/ai/model-profiles.d.ts +9 -9
  106. package/dist/features/ai/model-profiles.js +13 -13
  107. package/dist/features/ai/model-profiles.js.map +1 -1
  108. package/dist/features/ai/protocol/agent-ops.d.ts +2 -2
  109. package/dist/features/ai/protocol/agent-ops.js +1 -1
  110. package/dist/features/ai/protocol/agent-ops.js.map +1 -1
  111. package/dist/features/ai/protocol/block-lines.d.ts +7 -7
  112. package/dist/features/ai/protocol/block-lines.js +10 -10
  113. package/dist/features/ai/protocol/block-lines.js.map +1 -1
  114. package/dist/features/ai/protocol/chat.d.ts +5 -5
  115. package/dist/features/ai/protocol/chat.js +12 -12
  116. package/dist/features/ai/protocol/chat.js.map +1 -1
  117. package/dist/features/ai/protocol/generate.d.ts +1 -1
  118. package/dist/features/ai/protocol/generate.js +1 -1
  119. package/dist/features/ai/protocol/generate.js.map +1 -1
  120. package/dist/features/ai/protocol/index.d.ts +3 -3
  121. package/dist/features/ai/protocol/index.js +2 -2
  122. package/dist/features/ai/protocol/models.d.ts +3 -3
  123. package/dist/features/ai/protocol/models.js +3 -3
  124. package/dist/features/ai/protocol/models.js.map +1 -1
  125. package/dist/features/ai/protocol/schemas.d.ts +1 -1
  126. package/dist/features/ai/protocol/schemas.js +1 -1
  127. package/dist/features/ai/protocol/schemas.js.map +1 -1
  128. package/dist/features/ai/protocol/tasks.d.ts +5 -5
  129. package/dist/features/ai/protocol/tasks.js +12 -12
  130. package/dist/features/ai/protocol/tasks.js.map +1 -1
  131. package/dist/features/ai/react/AiSelectionMenu.js.map +1 -1
  132. package/dist/features/ai/react/ModelQuickSwitch.d.ts +4 -4
  133. package/dist/features/ai/react/ModelQuickSwitch.js +6 -6
  134. package/dist/features/ai/react/ModelQuickSwitch.js.map +1 -1
  135. package/dist/features/ai/react/SettingsAiTab.d.ts +1 -1
  136. package/dist/features/ai/react/SettingsAiTab.js +8 -8
  137. package/dist/features/ai/react/SettingsAiTab.js.map +1 -1
  138. package/dist/features/ai/react/SettingsModelProfiles.d.ts +1 -1
  139. package/dist/features/ai/react/SettingsModelProfiles.js +1 -1
  140. package/dist/features/ai/react/SettingsModelProfiles.js.map +1 -1
  141. package/dist/features/ai/react/use-ai-assistant.d.ts +1 -1
  142. package/dist/features/ai/react/use-ai-assistant.js +1 -1
  143. package/dist/features/ai/react/use-ai-assistant.js.map +1 -1
  144. package/dist/features/ai/react/use-model-profiles.d.ts +5 -5
  145. package/dist/features/ai/react/use-model-profiles.js +2 -2
  146. package/dist/features/ai/react/use-model-profiles.js.map +1 -1
  147. package/dist/features/ai/use-ai-assistant.d.ts +1 -1
  148. package/dist/features/ai/use-ai-assistant.js +1 -1
  149. package/dist/features/ai/use-ai-assistant.js.map +1 -1
  150. package/dist/features/ai/use-model-profiles.d.ts +4 -4
  151. package/dist/features/ai/use-model-profiles.js +2 -2
  152. package/dist/features/ai/use-model-profiles.js.map +1 -1
  153. package/dist/features/block-ui/block-actions.d.ts +8 -4
  154. package/dist/features/block-ui/block-actions.js +38 -22
  155. package/dist/features/block-ui/block-actions.js.map +1 -1
  156. package/dist/features/block-ui/block-target.d.ts +29 -0
  157. package/dist/features/block-ui/block-target.js +63 -0
  158. package/dist/features/block-ui/block-target.js.map +1 -0
  159. package/dist/features/block-ui/components/BlockHandles.js +3 -3
  160. package/dist/features/block-ui/components/BlockHandles.js.map +1 -1
  161. package/dist/features/block-ui/components/BlockUi.js +11 -23
  162. package/dist/features/block-ui/components/BlockUi.js.map +1 -1
  163. package/dist/features/block-ui/feature.d.ts +3 -2
  164. package/dist/features/block-ui/feature.js +3 -2
  165. package/dist/features/block-ui/feature.js.map +1 -1
  166. package/dist/features/block-ui/handle-geometry.js +12 -23
  167. package/dist/features/block-ui/handle-geometry.js.map +1 -1
  168. package/dist/features/block-ui/index.d.ts +2 -1
  169. package/dist/features/block-ui/index.js +2 -1
  170. package/dist/features/block-ui/react/BlockHandles.d.ts +1 -1
  171. package/dist/features/block-ui/react/BlockHandles.js +4 -4
  172. package/dist/features/block-ui/react/BlockHandles.js.map +1 -1
  173. package/dist/features/block-ui/react/BlockUi.js +13 -25
  174. package/dist/features/block-ui/react/BlockUi.js.map +1 -1
  175. package/dist/features/comments/model.js +1 -1
  176. package/dist/features/composites/accepted-children.d.ts +5 -4
  177. package/dist/features/composites/accepted-children.js +26 -26
  178. package/dist/features/composites/accepted-children.js.map +1 -1
  179. package/dist/features/composites/ai-brief.d.ts +4 -4
  180. package/dist/features/composites/ai-brief.js +14 -12
  181. package/dist/features/composites/ai-brief.js.map +1 -1
  182. package/dist/features/composites/anchors.d.ts +1 -1
  183. package/dist/features/composites/anchors.js.map +1 -1
  184. package/dist/features/composites/baskets.d.ts +1 -1
  185. package/dist/features/composites/baskets.js.map +1 -1
  186. package/dist/features/composites/bibliography-command.d.ts +1 -1
  187. package/dist/features/composites/bibliography-form.js +1 -1
  188. package/dist/features/composites/bibliography-form.js.map +1 -1
  189. package/dist/features/composites/bibliography.js.map +1 -1
  190. package/dist/features/composites/block-types-json.d.ts +38 -0
  191. package/dist/features/composites/block-types-json.js +122 -0
  192. package/dist/features/composites/block-types-json.js.map +1 -0
  193. package/dist/features/composites/block-types.d.ts +119 -0
  194. package/dist/features/composites/block-types.js +343 -0
  195. package/dist/features/composites/block-types.js.map +1 -0
  196. package/dist/features/composites/capabilities.js +109 -0
  197. package/dist/features/composites/capabilities.js.map +1 -0
  198. package/dist/features/composites/components/BibliographyEditor.js +5 -5
  199. package/dist/features/composites/components/BibliographyEditor.js.map +1 -1
  200. package/dist/features/composites/components/CompositeBasketMenu.js +2 -2
  201. package/dist/features/composites/components/CompositeBasketMenu.js.map +1 -1
  202. package/dist/features/composites/components/CompositeChrome.js +18 -8
  203. package/dist/features/composites/components/CompositeChrome.js.map +1 -1
  204. package/dist/features/composites/components/CompositeChrome.vue.d.ts +1 -1
  205. package/dist/features/composites/components/CompositeDetails.js +11 -10
  206. package/dist/features/composites/components/CompositeDetails.js.map +1 -1
  207. package/dist/features/composites/components/CompositeDetails.vue.d.ts +1 -1
  208. package/dist/features/composites/components/CompositeFieldEditor.js +7 -7
  209. package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
  210. package/dist/features/composites/components/CompositeFieldEditor.vue.d.ts +5 -5
  211. package/dist/features/composites/components/CompositeInspector.js +136 -113
  212. package/dist/features/composites/components/CompositeInspector.js.map +1 -1
  213. package/dist/features/composites/components/CompositeInspector.vue.d.ts +3 -3
  214. package/dist/features/composites/components/CompositeStatusMenu.js +2 -2
  215. package/dist/features/composites/components/CompositeStatusMenu.js.map +1 -1
  216. package/dist/features/composites/components/CompositeSummaryEditor.js +1 -1
  217. package/dist/features/composites/components/CompositeSummaryEditor.js.map +1 -1
  218. package/dist/features/composites/components/CompositeSummaryEditor.vue.d.ts +1 -1
  219. package/dist/features/composites/components/CompositeTable.js +2 -2
  220. package/dist/features/composites/components/CompositeTable.js.map +1 -1
  221. package/dist/features/composites/components/CompositeTagsEditor.js +1 -1
  222. package/dist/features/composites/components/CompositeTagsEditor.js.map +1 -1
  223. package/dist/features/composites/components/CompositeTagsEditor.vue.d.ts +1 -1
  224. package/dist/features/composites/components/CompositeView.js +19 -17
  225. package/dist/features/composites/components/CompositeView.js.map +1 -1
  226. package/dist/features/composites/components/DerivationBadge.js +15 -6
  227. package/dist/features/composites/components/DerivationBadge.js.map +1 -1
  228. package/dist/features/composites/components/FocusChip.js +1 -1
  229. package/dist/features/composites/components/FocusChip.js.map +1 -1
  230. package/dist/features/composites/components/FocusChip.vue.d.ts +1 -1
  231. package/dist/features/composites/components/ReferenceFieldSelect.js +3 -3
  232. package/dist/features/composites/components/ReferenceFieldSelect.js.map +1 -1
  233. package/dist/features/composites/components/ReferenceView.js +1 -1
  234. package/dist/features/composites/components/ReferenceView.js.map +1 -1
  235. package/dist/features/composites/components/SettingsEditingTab.js +18 -18
  236. package/dist/features/composites/components/SettingsEditingTab.js.map +1 -1
  237. package/dist/features/composites/components/SettingsEditingTab.vue.d.ts +3 -3
  238. package/dist/features/composites/convert.d.ts +4 -4
  239. package/dist/features/composites/convert.js +27 -28
  240. package/dist/features/composites/convert.js.map +1 -1
  241. package/dist/features/composites/derived-chrome.js +34 -28
  242. package/dist/features/composites/derived-chrome.js.map +1 -1
  243. package/dist/features/composites/editing-settings-keys.js +6 -6
  244. package/dist/features/composites/editing-settings-keys.js.map +1 -1
  245. package/dist/features/composites/feature.d.ts +10 -10
  246. package/dist/features/composites/feature.js +58 -46
  247. package/dist/features/composites/feature.js.map +1 -1
  248. package/dist/features/composites/fences.d.ts +3 -3
  249. package/dist/features/composites/fences.js +18 -13
  250. package/dist/features/composites/fences.js.map +1 -1
  251. package/dist/features/composites/focus.d.ts +10 -10
  252. package/dist/features/composites/focus.js +11 -11
  253. package/dist/features/composites/focus.js.map +1 -1
  254. package/dist/features/composites/heading-composites.d.ts +5 -5
  255. package/dist/features/composites/heading-composites.js +13 -16
  256. package/dist/features/composites/heading-composites.js.map +1 -1
  257. package/dist/features/composites/index.d.ts +20 -18
  258. package/dist/features/composites/index.js +9 -7
  259. package/dist/features/composites/inspector-model.d.ts +45 -22
  260. package/dist/features/composites/inspector-model.js +53 -14
  261. package/dist/features/composites/inspector-model.js.map +1 -1
  262. package/dist/features/composites/legacy.d.ts +5 -4
  263. package/dist/features/composites/legacy.js +16 -23
  264. package/dist/features/composites/legacy.js.map +1 -1
  265. package/dist/features/composites/markdown-export.js +3 -3
  266. package/dist/features/composites/markdown-export.js.map +1 -1
  267. package/dist/features/composites/merge.d.ts +8 -8
  268. package/dist/features/composites/merge.js +23 -22
  269. package/dist/features/composites/merge.js.map +1 -1
  270. package/dist/features/composites/meta-display.js +5 -5
  271. package/dist/features/composites/meta-display.js.map +1 -1
  272. package/dist/features/composites/meta-keys.d.ts +5 -5
  273. package/dist/features/composites/meta-keys.js +8 -8
  274. package/dist/features/composites/meta-keys.js.map +1 -1
  275. package/dist/features/composites/node-views.d.ts +3 -3
  276. package/dist/features/composites/node-views.js +2 -2
  277. package/dist/features/composites/node-views.js.map +1 -1
  278. package/dist/features/composites/nodes.d.ts +13 -13
  279. package/dist/features/composites/nodes.js +100 -77
  280. package/dist/features/composites/nodes.js.map +1 -1
  281. package/dist/features/composites/outline.d.ts +15 -12
  282. package/dist/features/composites/outline.js +24 -21
  283. package/dist/features/composites/outline.js.map +1 -1
  284. package/dist/features/composites/properties.d.ts +51 -0
  285. package/dist/features/composites/properties.js +89 -0
  286. package/dist/features/composites/properties.js.map +1 -0
  287. package/dist/features/composites/react/BibliographyEditor.js +5 -5
  288. package/dist/features/composites/react/BibliographyEditor.js.map +1 -1
  289. package/dist/features/composites/react/CompositeBasketMenu.js +2 -2
  290. package/dist/features/composites/react/CompositeBasketMenu.js.map +1 -1
  291. package/dist/features/composites/react/CompositeChrome.d.ts +1 -1
  292. package/dist/features/composites/react/CompositeChrome.js +15 -6
  293. package/dist/features/composites/react/CompositeChrome.js.map +1 -1
  294. package/dist/features/composites/react/CompositeDetails.d.ts +1 -1
  295. package/dist/features/composites/react/CompositeDetails.js +11 -10
  296. package/dist/features/composites/react/CompositeDetails.js.map +1 -1
  297. package/dist/features/composites/react/CompositeFieldEditor.d.ts +5 -5
  298. package/dist/features/composites/react/CompositeFieldEditor.js +6 -6
  299. package/dist/features/composites/react/CompositeFieldEditor.js.map +1 -1
  300. package/dist/features/composites/react/CompositeInspector.d.ts +3 -3
  301. package/dist/features/composites/react/CompositeInspector.js +142 -128
  302. package/dist/features/composites/react/CompositeInspector.js.map +1 -1
  303. package/dist/features/composites/react/CompositeStatusMenu.js +2 -2
  304. package/dist/features/composites/react/CompositeStatusMenu.js.map +1 -1
  305. package/dist/features/composites/react/CompositeSummaryEditor.d.ts +1 -1
  306. package/dist/features/composites/react/CompositeSummaryEditor.js +1 -1
  307. package/dist/features/composites/react/CompositeSummaryEditor.js.map +1 -1
  308. package/dist/features/composites/react/CompositeTable.d.ts +1 -1
  309. package/dist/features/composites/react/CompositeTable.js +3 -3
  310. package/dist/features/composites/react/CompositeTable.js.map +1 -1
  311. package/dist/features/composites/react/CompositeTagsEditor.d.ts +1 -1
  312. package/dist/features/composites/react/CompositeTagsEditor.js +1 -1
  313. package/dist/features/composites/react/CompositeTagsEditor.js.map +1 -1
  314. package/dist/features/composites/react/CompositeView.js +17 -15
  315. package/dist/features/composites/react/CompositeView.js.map +1 -1
  316. package/dist/features/composites/react/DerivationBadge.js +13 -4
  317. package/dist/features/composites/react/DerivationBadge.js.map +1 -1
  318. package/dist/features/composites/react/FocusChip.d.ts +1 -1
  319. package/dist/features/composites/react/FocusChip.js +1 -1
  320. package/dist/features/composites/react/FocusChip.js.map +1 -1
  321. package/dist/features/composites/react/ReferenceFieldSelect.js +3 -3
  322. package/dist/features/composites/react/ReferenceFieldSelect.js.map +1 -1
  323. package/dist/features/composites/react/ReferenceView.d.ts +1 -1
  324. package/dist/features/composites/react/ReferenceView.js +1 -1
  325. package/dist/features/composites/react/ReferenceView.js.map +1 -1
  326. package/dist/features/composites/react/SettingsEditingTab.d.ts +4 -4
  327. package/dist/features/composites/react/SettingsEditingTab.js +20 -20
  328. package/dist/features/composites/react/SettingsEditingTab.js.map +1 -1
  329. package/dist/features/composites/react.js +1 -1
  330. package/dist/features/composites/react.js.map +1 -1
  331. package/dist/features/composites/reference-ai.js +1 -1
  332. package/dist/features/composites/reference-ai.js.map +1 -1
  333. package/dist/features/composites/reference-label.d.ts +3 -3
  334. package/dist/features/composites/reference-label.js +6 -6
  335. package/dist/features/composites/reference-label.js.map +1 -1
  336. package/dist/features/composites/reference-suggestion.d.ts +1 -1
  337. package/dist/features/composites/reference-suggestion.js +3 -3
  338. package/dist/features/composites/reference-suggestion.js.map +1 -1
  339. package/dist/features/composites/reference-text.d.ts +2 -2
  340. package/dist/features/composites/reference-text.js +4 -4
  341. package/dist/features/composites/reference-text.js.map +1 -1
  342. package/dist/features/composites/reference.d.ts +3 -3
  343. package/dist/features/composites/reference.js +1 -1
  344. package/dist/features/composites/reference.js.map +1 -1
  345. package/dist/features/composites/reveal-source.d.ts +3 -3
  346. package/dist/features/composites/reveal-source.js +6 -6
  347. package/dist/features/composites/reveal-source.js.map +1 -1
  348. package/dist/features/composites/rows-model.d.ts +2 -2
  349. package/dist/features/composites/rows-model.js +4 -3
  350. package/dist/features/composites/rows-model.js.map +1 -1
  351. package/dist/features/composites/rows.d.ts +16 -28
  352. package/dist/features/composites/rows.js +20 -54
  353. package/dist/features/composites/rows.js.map +1 -1
  354. package/dist/features/composites/schema.d.ts +12 -11
  355. package/dist/features/composites/schema.js +10 -9
  356. package/dist/features/composites/schema.js.map +1 -1
  357. package/dist/features/composites/source.d.ts +20 -0
  358. package/dist/features/composites/source.js +40 -0
  359. package/dist/features/composites/source.js.map +1 -0
  360. package/dist/features/composites/split.d.ts +11 -11
  361. package/dist/features/composites/split.js +20 -20
  362. package/dist/features/composites/split.js.map +1 -1
  363. package/dist/features/composites/structure-mode.js +3 -3
  364. package/dist/features/composites/structure-mode.js.map +1 -1
  365. package/dist/features/composites/table-model.js +2 -2
  366. package/dist/features/composites/table-model.js.map +1 -1
  367. package/dist/features/composites/use-composite-inspector.js +3 -1
  368. package/dist/features/composites/use-composite-inspector.js.map +1 -1
  369. package/dist/features/composites/use-composite-rows.d.ts +2 -2
  370. package/dist/features/composites/use-composite-rows.js.map +1 -1
  371. package/dist/features/composites/vue.js +1 -1
  372. package/dist/features/composites/vue.js.map +1 -1
  373. package/dist/features/image-studio/components/ImageStudioDialog.js +150 -87
  374. package/dist/features/image-studio/components/ImageStudioDialog.js.map +1 -1
  375. package/dist/features/image-studio/components/ImageStudioDialog.vue.d.ts +5 -1
  376. package/dist/features/image-studio/components/ImageStudioLibraryPanel.js +186 -0
  377. package/dist/features/image-studio/components/ImageStudioLibraryPanel.js.map +1 -0
  378. package/dist/features/image-studio/components/ImageStudioLibraryTile.js +134 -0
  379. package/dist/features/image-studio/components/ImageStudioLibraryTile.js.map +1 -0
  380. package/dist/features/image-studio/components/ImageStudioView.js.map +1 -1
  381. package/dist/features/image-studio/feature.d.ts +1 -1
  382. package/dist/features/image-studio/feature.js +1 -1
  383. package/dist/features/image-studio/feature.js.map +1 -1
  384. package/dist/features/image-studio/index.d.ts +3 -2
  385. package/dist/features/image-studio/index.js +2 -2
  386. package/dist/features/image-studio/library.d.ts +35 -0
  387. package/dist/features/image-studio/node-core.d.ts +3 -3
  388. package/dist/features/image-studio/node-core.js +1 -1
  389. package/dist/features/image-studio/node-core.js.map +1 -1
  390. package/dist/features/image-studio/node-store.d.ts +1 -1
  391. package/dist/features/image-studio/node-store.js +1 -1
  392. package/dist/features/image-studio/node-store.js.map +1 -1
  393. package/dist/features/image-studio/react/ImageStudioDialog.d.ts +1 -1
  394. package/dist/features/image-studio/react/ImageStudioDialog.js +46 -5
  395. package/dist/features/image-studio/react/ImageStudioDialog.js.map +1 -1
  396. package/dist/features/image-studio/react/ImageStudioLibraryPanel.js +141 -0
  397. package/dist/features/image-studio/react/ImageStudioLibraryPanel.js.map +1 -0
  398. package/dist/features/image-studio/react/ImageStudioLibraryTile.js +105 -0
  399. package/dist/features/image-studio/react/ImageStudioLibraryTile.js.map +1 -0
  400. package/dist/features/image-studio/react/ImageStudioView.js +1 -1
  401. package/dist/features/image-studio/react/ImageStudioView.js.map +1 -1
  402. package/dist/features/image-studio/react/store.d.ts +8 -3
  403. package/dist/features/image-studio/react/store.js.map +1 -1
  404. package/dist/features/image-studio/react.d.ts +4 -3
  405. package/dist/features/image-studio/react.js +3 -3
  406. package/dist/features/image-studio/react.js.map +1 -1
  407. package/dist/features/image-studio/schema.d.ts +1 -1
  408. package/dist/features/image-studio/schema.js +1 -1
  409. package/dist/features/image-studio/schema.js.map +1 -1
  410. package/dist/features/image-studio/state.d.ts +8 -3
  411. package/dist/features/image-studio/state.js +11 -3
  412. package/dist/features/image-studio/state.js.map +1 -1
  413. package/dist/features/image-studio/store.d.ts +8 -3
  414. package/dist/features/image-studio/vue.d.ts +4 -3
  415. package/dist/features/image-studio/vue.js +3 -3
  416. package/dist/features/image-studio/vue.js.map +1 -1
  417. package/dist/features/mentions/tag.js +2 -1
  418. package/dist/features/mentions/tag.js.map +1 -1
  419. package/dist/features/themes/components/SettingsAppearanceTab.js +1 -1
  420. package/dist/features/themes/components/SettingsAppearanceTab.js.map +1 -1
  421. package/dist/features/themes/feature.d.ts +1 -1
  422. package/dist/features/themes/feature.js.map +1 -1
  423. package/dist/features/themes/react/SettingsAppearanceTab.d.ts +1 -1
  424. package/dist/features/themes/react/SettingsAppearanceTab.js +1 -1
  425. package/dist/features/themes/react/SettingsAppearanceTab.js.map +1 -1
  426. package/dist/features/themes/theme-runtime.js +1 -1
  427. package/dist/features/themes/theme-runtime.js.map +1 -1
  428. package/dist/features/transcript/TranscriptSegmentView.js +1 -1
  429. package/dist/features/transcript/TranscriptSegmentView.js.map +1 -1
  430. package/dist/features/transcript/react/TranscriptSegmentView.js +1 -1
  431. package/dist/features/transcript/react/TranscriptSegmentView.js.map +1 -1
  432. package/dist/features/transcript/segment-node.js.map +1 -1
  433. package/dist/features/transfer/feature.js +1 -1
  434. package/dist/features/transfer/feature.js.map +1 -1
  435. package/dist/features/transfer/transforms.d.ts +4 -4
  436. package/dist/features/transfer/transforms.js +12 -12
  437. package/dist/features/transfer/transforms.js.map +1 -1
  438. package/dist/i18n/de/ai.js +4 -4
  439. package/dist/i18n/de/ai.js.map +1 -1
  440. package/dist/i18n/de/authors.js +1 -1
  441. package/dist/i18n/de/authors.js.map +1 -1
  442. package/dist/i18n/de/comments.js +1 -1
  443. package/dist/i18n/de/comments.js.map +1 -1
  444. package/dist/i18n/de/composites.js +62 -59
  445. package/dist/i18n/de/composites.js.map +1 -1
  446. package/dist/i18n/de/image-studio.js +11 -2
  447. package/dist/i18n/de/image-studio.js.map +1 -1
  448. package/dist/i18n/de/integrations.js +20 -20
  449. package/dist/i18n/de/integrations.js.map +1 -1
  450. package/dist/i18n/de/markdown.js +1 -1
  451. package/dist/i18n/de/markdown.js.map +1 -1
  452. package/dist/i18n/de/palette.js +1 -1
  453. package/dist/i18n/de/palette.js.map +1 -1
  454. package/dist/i18n/de/themes.js +3 -3
  455. package/dist/i18n/de/themes.js.map +1 -1
  456. package/dist/i18n/de/transfer.js +2 -2
  457. package/dist/i18n/de/transfer.js.map +1 -1
  458. package/dist/i18n/de/tree.js +6 -6
  459. package/dist/i18n/de/tree.js.map +1 -1
  460. package/dist/i18n/de.d.ts +110 -98
  461. package/dist/i18n/en/ai.js +2 -2
  462. package/dist/i18n/en/ai.js.map +1 -1
  463. package/dist/i18n/en/composites.js +64 -61
  464. package/dist/i18n/en/composites.js.map +1 -1
  465. package/dist/i18n/en/image-studio.js +9 -0
  466. package/dist/i18n/en/image-studio.js.map +1 -1
  467. package/dist/i18n/en/integrations.js +9 -9
  468. package/dist/i18n/en/integrations.js.map +1 -1
  469. package/dist/i18n/en/markdown.js +1 -1
  470. package/dist/i18n/en/markdown.js.map +1 -1
  471. package/dist/i18n/en/palette.js +1 -1
  472. package/dist/i18n/en/palette.js.map +1 -1
  473. package/dist/i18n/en/themes.js +4 -4
  474. package/dist/i18n/en/themes.js.map +1 -1
  475. package/dist/i18n/en/tree.js +5 -5
  476. package/dist/i18n/en/tree.js.map +1 -1
  477. package/dist/index.d.ts +4 -1
  478. package/dist/integrations/composite-ai/bibliography-fetch.d.ts +6 -6
  479. package/dist/integrations/composite-ai/bibliography-fetch.js +19 -19
  480. package/dist/integrations/composite-ai/bibliography-fetch.js.map +1 -1
  481. package/dist/integrations/composite-ai/composite-fill.d.ts +4 -4
  482. package/dist/integrations/composite-ai/composite-fill.js +5 -5
  483. package/dist/integrations/composite-ai/composite-fill.js.map +1 -1
  484. package/dist/integrations/composite-ai/composite-summary.d.ts +2 -2
  485. package/dist/integrations/composite-ai/composite-summary.js +5 -5
  486. package/dist/integrations/composite-ai/composite-summary.js.map +1 -1
  487. package/dist/integrations/composite-ai/derive.d.ts +17 -17
  488. package/dist/integrations/composite-ai/derive.js +27 -26
  489. package/dist/integrations/composite-ai/derive.js.map +1 -1
  490. package/dist/integrations/composite-ai/index.d.ts +14 -15
  491. package/dist/integrations/composite-ai/index.js +98 -77
  492. package/dist/integrations/composite-ai/index.js.map +1 -1
  493. package/dist/integrations/composite-ai/outline-sanitize.d.ts +1 -1
  494. package/dist/integrations/composite-ai/outline-sanitize.js +1 -1
  495. package/dist/integrations/composite-ai/outline-sanitize.js.map +1 -1
  496. package/dist/integrations/composite-ai/rendition.d.ts +9 -9
  497. package/dist/integrations/composite-ai/rendition.js +27 -27
  498. package/dist/integrations/composite-ai/rendition.js.map +1 -1
  499. package/dist/integrations/composite-ai/split.d.ts +8 -8
  500. package/dist/integrations/composite-ai/split.js +12 -12
  501. package/dist/integrations/composite-ai/split.js.map +1 -1
  502. package/dist/integrations/composite-ai/transfer-transforms.d.ts +2 -2
  503. package/dist/integrations/composite-ai/transfer-transforms.js +11 -11
  504. package/dist/integrations/composite-ai/transfer-transforms.js.map +1 -1
  505. package/dist/integrations/composite-media/index.d.ts +4 -3
  506. package/dist/integrations/composite-media/index.js +20 -14
  507. package/dist/integrations/composite-media/index.js.map +1 -1
  508. package/dist/markdown/MarkdownSurface.vue.d.ts +7 -7
  509. package/dist/markdown/document.js +1 -1
  510. package/dist/markdown/document.js.map +1 -1
  511. package/dist/nuxt/module.d.ts +48 -24
  512. package/dist/nuxt/module.js.map +1 -1
  513. package/dist/nuxt/runtime/server/plugins/editor-server.js +3 -2
  514. package/dist/nuxt/runtime/server/plugins/editor-server.js.map +1 -1
  515. package/dist/presets/compose.d.ts +6 -6
  516. package/dist/presets/compose.js +7 -4
  517. package/dist/presets/compose.js.map +1 -1
  518. package/dist/react/AdvancedEditor.d.ts +2 -2
  519. package/dist/react/AdvancedEditor.js +1 -1
  520. package/dist/react/AdvancedEditor.js.map +1 -1
  521. package/dist/react/compose.d.ts +1 -1
  522. package/dist/react/compose.js +1 -1
  523. package/dist/react/compose.js.map +1 -1
  524. package/dist/react/composed-surface.d.ts +5 -5
  525. package/dist/react/composed-surface.js +2 -2
  526. package/dist/react/composed-surface.js.map +1 -1
  527. package/dist/server/ai.d.ts +7 -7
  528. package/dist/server/ai.js +1 -1
  529. package/dist/server/ai.js.map +1 -1
  530. package/dist/server/auth.d.ts +1 -1
  531. package/dist/server/collab-state.d.ts +1 -1
  532. package/dist/server/collab-state.js.map +1 -1
  533. package/dist/server/collab.d.ts +4 -4
  534. package/dist/server/collab.js +22 -17
  535. package/dist/server/collab.js.map +1 -1
  536. package/dist/server/handlers/ai.d.ts +9 -6
  537. package/dist/server/handlers/ai.js +13 -17
  538. package/dist/server/handlers/ai.js.map +1 -1
  539. package/dist/server/handlers/context.d.ts +4 -0
  540. package/dist/server/handlers/context.js.map +1 -1
  541. package/dist/server/handlers/editor.d.ts +33 -32
  542. package/dist/server/handlers/editor.js +13 -8
  543. package/dist/server/handlers/editor.js.map +1 -1
  544. package/dist/server/handlers/images.d.ts +1 -1
  545. package/dist/server/handlers/images.js +1 -1
  546. package/dist/server/handlers/images.js.map +1 -1
  547. package/dist/server/host.d.ts +4 -0
  548. package/dist/server/host.js +10 -2
  549. package/dist/server/host.js.map +1 -1
  550. package/dist/server/index.d.ts +3 -3
  551. package/dist/server/ports.d.ts +8 -8
  552. package/dist/server/ports.js.map +1 -1
  553. package/dist/settings/index.d.ts +20 -19
  554. package/dist/settings/index.js +25 -24
  555. package/dist/settings/index.js.map +1 -1
  556. package/dist/settings/migrate.d.ts +18 -0
  557. package/dist/settings/migrate.js +46 -0
  558. package/dist/settings/migrate.js.map +1 -0
  559. package/dist/settings/values.d.ts +12 -12
  560. package/dist/settings/values.js +11 -11
  561. package/dist/settings/values.js.map +1 -1
  562. package/dist/styles/composites.css +10 -10
  563. package/dist/tree/DocumentTree.js +12 -5
  564. package/dist/tree/DocumentTree.js.map +1 -1
  565. package/dist/tree/drop-rules.js +5 -5
  566. package/dist/tree/drop-rules.js.map +1 -1
  567. package/dist/tree/react/DocumentTree.js +14 -5
  568. package/dist/tree/react/DocumentTree.js.map +1 -1
  569. package/dist/tree/tree-host.js +5 -5
  570. package/dist/tree/tree-host.js.map +1 -1
  571. package/dist/tree/tree-items.js +34 -28
  572. package/dist/tree/tree-items.js.map +1 -1
  573. package/dist/tree/tree-model.js +16 -16
  574. package/dist/tree/tree-model.js.map +1 -1
  575. package/dist/tree/tree-rows.js +2 -2
  576. package/dist/tree/tree-rows.js.map +1 -1
  577. package/dist/tree/tree-view-model.d.ts +2 -2
  578. package/dist/tree/tree-view-model.js.map +1 -1
  579. package/dist/vue/AdvancedEditor.js +2 -2
  580. package/dist/vue/AdvancedEditor.js.map +1 -1
  581. package/dist/vue/AdvancedEditor.vue.d.ts +10 -10
  582. package/dist/vue/SimpleEditor.vue.d.ts +4 -4
  583. package/dist/vue/components/EditorSurface.vue.d.ts +4 -4
  584. package/dist/vue/compose.d.ts +1 -1
  585. package/dist/vue/compose.js +1 -1
  586. package/dist/vue/compose.js.map +1 -1
  587. package/package.json +1 -1
  588. package/dist/features/composites/derivation.d.ts +0 -62
  589. package/dist/features/composites/derivation.js +0 -102
  590. package/dist/features/composites/derivation.js.map +0 -1
  591. package/dist/features/composites/kinds.d.ts +0 -89
  592. package/dist/features/composites/kinds.js +0 -285
  593. package/dist/features/composites/kinds.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"feature.js","names":[],"sources":["../../../src/features/ai/feature.ts"],"sourcesContent":["import { type AnyExtension, Extension } from '@tiptap/core'\nimport type { CommandDef, EditorFeature, FeatureContext, ToolbarGroupDef } from '../../core'\nimport { AiReview } from './ai-review'\nimport { AiSelectionHighlight } from './ai-selection-highlight'\nimport { aiBlockAction, aiCommand } from './block-actions'\nimport { completionFetcher, ghostAutocomplete } from './ghost-autocomplete'\nimport { modelProfiles } from './model-profiles'\n\n/** What a framework binding supplies to the AI feature: the components of its UI layer. */\nexport interface AiUi<C> {\n /** The selection bubble menu and the caret menu (rewrite, translate, generate; preview and apply). */\n selectionMenu: C\n /** The accept/reject bar of the in-document review. */\n reviewBar: C\n /** The „KI“ settings tab component of the framework. */\n settingsTab: C\n}\n\n/** Pause after the last keystroke before an autocomplete suggestion is requested (ms). */\nconst GHOST_DEBOUNCE = 500\n\n// Mod-Shift-k toggles this editor's AI sidebar while the editor has focus (shown on the toolbar's „KI-Seitenleiste“).\nfunction sidebarShortcut(ctx: FeatureContext): AnyExtension {\n return Extension.create({\n name: 'aiSidebarShortcut',\n addKeyboardShortcuts: () => ({\n 'Mod-Shift-k': () => {\n ctx.ui.toggleSidebar()\n return true\n },\n }),\n })\n}\n\nconst aiToolbarGroups: ToolbarGroupDef[] = [{ id: 'ai', order: 1000, labelKey: 'palette.group.ai' }]\n\nfunction aiCommands<C>(ctx: FeatureContext): CommandDef<C>[] {\n return [\n {\n id: 'sidebar',\n toolbar: { group: 'ai', order: 10 },\n icon: 'i-lucide-panel-right',\n label: ctx.t('ai.toolbar.sidebar'),\n kbds: ['meta', 'shift', 'k'],\n run: () => ctx.ui.toggleSidebar(),\n },\n {\n id: 'autocomplete',\n toolbar: { group: 'ai', order: 20 },\n icon: 'i-lucide-wand-sparkles',\n label: ctx.t('ai.toolbar.autocomplete'),\n active: () => ctx.settings.get().ai.autocomplete,\n run: () => { ctx.settings.update((s) => { s.ai.autocomplete = !s.ai.autocomplete }) },\n },\n aiCommand(ctx),\n ]\n}\n\n/**\n * AI on a core editor: the selection menu and `/ai` (rewrite and generate at the caret), in-document review of\n * rewrites, ghost autocomplete, the model profiles and the `ai` settings tab, the „Mit KI bearbeiten“ block action, the\n * toolbar group (sidebar toggle, autocomplete switch) and Mod-Shift-k. The sidebar (`AiSidebar`) and the model switch\n * are components the host places. Reads the document model through the merged `aiContext` (kinds, host blocks,\n * structure) and the `formatAiResult` contribution of other\n * features (defaults: no kinds, no blocks, flat structure) and maps positions through the preset's anchor resolver, so it imports\n * no composites, transcript, media, mentions, collaboration or Yjs code. The model profiles come from the app context\n * (`modelProfiles(ctx.app)`), shared by all editors of the app.\n */\nexport function aiFeatureCore<C>(ui: AiUi<C>): EditorFeature<C> {\n return {\n id: 'ai',\n dimension: 'ai',\n backend: ['ai'],\n extensions: ctx => [\n AiSelectionHighlight,\n AiReview,\n ghostAutocomplete({\n settings: ctx.settings,\n debounce: GHOST_DEBOUNCE,\n fetchSuggestion: completionFetcher({ ai: ctx.backend.ai, modelRef: modelProfiles(ctx.app).modelRef }),\n }),\n sidebarShortcut(ctx),\n ],\n toolbarGroups: aiToolbarGroups,\n commands: aiCommands<C>,\n blockActions: ctx => [aiBlockAction(ctx)],\n overlays: [ui.selectionMenu, ui.reviewBar],\n settingsTabs: ctx => [{ id: 'ai', label: ctx.t('ai.tab'), icon: 'i-lucide-sparkles', component: ui.settingsTab }],\n }\n}\n"],"mappings":";;;;;;;;AAmBA,MAAM,iBAAiB;AAGvB,SAAS,gBAAgB,KAAmC;CAC1D,OAAO,UAAU,OAAO;EACtB,MAAM;EACN,6BAA6B,EAC3B,qBAAqB;GACnB,IAAI,GAAG,cAAc;GACrB,OAAO;EACT,EACF;CACF,CAAC;AACH;AAEA,MAAM,kBAAqC,CAAC;CAAE,IAAI;CAAM,OAAO;CAAM,UAAU;AAAmB,CAAC;AAEnG,SAAS,WAAc,KAAsC;CAC3D,OAAO;EACL;GACE,IAAI;GACJ,SAAS;IAAE,OAAO;IAAM,OAAO;GAAG;GAClC,MAAM;GACN,OAAO,IAAI,EAAE,oBAAoB;GACjC,MAAM;IAAC;IAAQ;IAAS;GAAG;GAC3B,WAAW,IAAI,GAAG,cAAc;EAClC;EACA;GACE,IAAI;GACJ,SAAS;IAAE,OAAO;IAAM,OAAO;GAAG;GAClC,MAAM;GACN,OAAO,IAAI,EAAE,yBAAyB;GACtC,cAAc,IAAI,SAAS,IAAI,CAAC,CAAC,GAAG;GACpC,WAAW;IAAE,IAAI,SAAS,QAAQ,MAAM;KAAE,EAAE,GAAG,eAAe,CAAC,EAAE,GAAG;IAAa,CAAC;GAAE;EACtF;EACA,UAAU,GAAG;CACf;AACF;;;;;;;;;;;AAYA,SAAgB,cAAiB,IAA+B;CAC9D,OAAO;EACL,IAAI;EACJ,WAAW;EACX,SAAS,CAAC,IAAI;EACd,aAAY,QAAO;GACjB;GACA;GACA,kBAAkB;IAChB,UAAU,IAAI;IACd,UAAU;IACV,iBAAiB,kBAAkB;KAAE,IAAI,IAAI,QAAQ;KAAI,UAAU,cAAc,IAAI,GAAG,CAAC,CAAC;IAAS,CAAC;GACtG,CAAC;GACD,gBAAgB,GAAG;EACrB;EACA,eAAe;EACf,UAAU;EACV,eAAc,QAAO,CAAC,cAAc,GAAG,CAAC;EACxC,UAAU,CAAC,GAAG,eAAe,GAAG,SAAS;EACzC,eAAc,QAAO,CAAC;GAAE,IAAI;GAAM,OAAO,IAAI,EAAE,QAAQ;GAAG,MAAM;GAAqB,WAAW,GAAG;EAAY,CAAC;CAClH;AACF"}
1
+ {"version":3,"file":"feature.js","names":[],"sources":["../../../src/features/ai/feature.ts"],"sourcesContent":["import { type AnyExtension, Extension } from '@tiptap/core'\nimport type { CommandDef, EditorFeature, FeatureContext, ToolbarGroupDef } from '../../core'\nimport { AiReview } from './ai-review'\nimport { AiSelectionHighlight } from './ai-selection-highlight'\nimport { aiBlockAction, aiCommand } from './block-actions'\nimport { completionFetcher, ghostAutocomplete } from './ghost-autocomplete'\nimport { modelProfiles } from './model-profiles'\n\n/** What a framework binding supplies to the AI feature: the components of its UI layer. */\nexport interface AiUi<C> {\n /** The selection bubble menu and the caret menu (rewrite, translate, generate; preview and apply). */\n selectionMenu: C\n /** The accept/reject bar of the in-document review. */\n reviewBar: C\n /** The „KI“ settings tab component of the framework. */\n settingsTab: C\n}\n\n/** Pause after the last keystroke before an autocomplete suggestion is requested (ms). */\nconst GHOST_DEBOUNCE = 500\n\n// Mod-Shift-k toggles this editor's AI sidebar while the editor has focus (shown on the toolbar's „KI-Seitenleiste“).\nfunction sidebarShortcut(ctx: FeatureContext): AnyExtension {\n return Extension.create({\n name: 'aiSidebarShortcut',\n addKeyboardShortcuts: () => ({\n 'Mod-Shift-k': () => {\n ctx.ui.toggleSidebar()\n return true\n },\n }),\n })\n}\n\nconst aiToolbarGroups: ToolbarGroupDef[] = [{ id: 'ai', order: 1000, labelKey: 'palette.group.ai' }]\n\nfunction aiCommands<C>(ctx: FeatureContext): CommandDef<C>[] {\n return [\n {\n id: 'sidebar',\n toolbar: { group: 'ai', order: 10 },\n icon: 'i-lucide-panel-right',\n label: ctx.t('ai.toolbar.sidebar'),\n kbds: ['meta', 'shift', 'k'],\n run: () => ctx.ui.toggleSidebar(),\n },\n {\n id: 'autocomplete',\n toolbar: { group: 'ai', order: 20 },\n icon: 'i-lucide-wand-sparkles',\n label: ctx.t('ai.toolbar.autocomplete'),\n active: () => ctx.settings.get().ai.autocomplete,\n run: () => { ctx.settings.update((s) => { s.ai.autocomplete = !s.ai.autocomplete }) },\n },\n aiCommand(ctx),\n ]\n}\n\n/**\n * AI on a core editor: the selection menu and `/ai` (rewrite and generate at the caret), in-document review of\n * rewrites, ghost autocomplete, the model profiles and the `ai` settings tab, the „Mit KI bearbeiten“ block action, the\n * toolbar group (sidebar toggle, autocomplete switch) and Mod-Shift-k. The sidebar (`AiSidebar`) and the model switch\n * are components the host places. Reads the document model through the merged `aiContext` (Block types, host blocks,\n * structure) and the `formatAiResult` contribution of other\n * features (defaults: no Block types, no blocks, flat structure) and maps positions through the preset's anchor resolver, so it imports\n * no composites, transcript, media, mentions, collaboration or Yjs code. The model profiles come from the app context\n * (`modelProfiles(ctx.app)`), shared by all editors of the app.\n */\nexport function aiFeatureCore<C>(ui: AiUi<C>): EditorFeature<C> {\n return {\n id: 'ai',\n dimension: 'ai',\n backend: ['ai'],\n extensions: ctx => [\n AiSelectionHighlight,\n AiReview,\n ghostAutocomplete({\n settings: ctx.settings,\n debounce: GHOST_DEBOUNCE,\n fetchSuggestion: completionFetcher({ ai: ctx.backend.ai, modelRef: modelProfiles(ctx.app).modelRef }),\n }),\n sidebarShortcut(ctx),\n ],\n toolbarGroups: aiToolbarGroups,\n commands: aiCommands<C>,\n blockActions: ctx => [aiBlockAction(ctx)],\n overlays: [ui.selectionMenu, ui.reviewBar],\n settingsTabs: ctx => [{ id: 'ai', label: ctx.t('ai.tab'), icon: 'i-lucide-sparkles', component: ui.settingsTab }],\n }\n}\n"],"mappings":";;;;;;;;AAmBA,MAAM,iBAAiB;AAGvB,SAAS,gBAAgB,KAAmC;CAC1D,OAAO,UAAU,OAAO;EACtB,MAAM;EACN,6BAA6B,EAC3B,qBAAqB;GACnB,IAAI,GAAG,cAAc;GACrB,OAAO;EACT,EACF;CACF,CAAC;AACH;AAEA,MAAM,kBAAqC,CAAC;CAAE,IAAI;CAAM,OAAO;CAAM,UAAU;AAAmB,CAAC;AAEnG,SAAS,WAAc,KAAsC;CAC3D,OAAO;EACL;GACE,IAAI;GACJ,SAAS;IAAE,OAAO;IAAM,OAAO;GAAG;GAClC,MAAM;GACN,OAAO,IAAI,EAAE,oBAAoB;GACjC,MAAM;IAAC;IAAQ;IAAS;GAAG;GAC3B,WAAW,IAAI,GAAG,cAAc;EAClC;EACA;GACE,IAAI;GACJ,SAAS;IAAE,OAAO;IAAM,OAAO;GAAG;GAClC,MAAM;GACN,OAAO,IAAI,EAAE,yBAAyB;GACtC,cAAc,IAAI,SAAS,IAAI,CAAC,CAAC,GAAG;GACpC,WAAW;IAAE,IAAI,SAAS,QAAQ,MAAM;KAAE,EAAE,GAAG,eAAe,CAAC,EAAE,GAAG;IAAa,CAAC;GAAE;EACtF;EACA,UAAU,GAAG;CACf;AACF;;;;;;;;;;;AAYA,SAAgB,cAAiB,IAA+B;CAC9D,OAAO;EACL,IAAI;EACJ,WAAW;EACX,SAAS,CAAC,IAAI;EACd,aAAY,QAAO;GACjB;GACA;GACA,kBAAkB;IAChB,UAAU,IAAI;IACd,UAAU;IACV,iBAAiB,kBAAkB;KAAE,IAAI,IAAI,QAAQ;KAAI,UAAU,cAAc,IAAI,GAAG,CAAC,CAAC;IAAS,CAAC;GACtG,CAAC;GACD,gBAAgB,GAAG;EACrB;EACA,eAAe;EACf,UAAU;EACV,eAAc,QAAO,CAAC,cAAc,GAAG,CAAC;EACxC,UAAU,CAAC,GAAG,eAAe,GAAG,SAAS;EACzC,eAAc,QAAO,CAAC;GAAE,IAAI;GAAM,OAAO,IAAI,EAAE,QAAQ;GAAG,MAAM;GAAqB,WAAW,GAAG;EAAY,CAAC;CAClH;AACF"}
@@ -1,5 +1,5 @@
1
1
  import { Store } from "../../core/store.js";
2
- import { ModelSlot } from "../../settings/values.js";
2
+ import { ModelRole } from "../../settings/values.js";
3
3
  import { EditorSettings } from "../../settings/index.js";
4
4
  import { EditorBackend } from "../../core/backend.js";
5
5
  import { ModelRef } from "../../core/backend-types.js";
@@ -27,13 +27,13 @@ interface GhostState {
27
27
  activity: number;
28
28
  }
29
29
  export declare const ghostAutocompleteKey: PluginKey<GhostState>;
30
- /** What the suggestion source needs of the app: its AI port and the model profile of a slot (`useModelProfiles`). */
30
+ /** What the suggestion source needs of the app: its AI port and the model profile of a Model role (`useModelProfiles`). */
31
31
  export interface CompletionHost {
32
32
  /** `EditorContext.backend.ai`; without it there are no suggestions. */
33
33
  ai: EditorBackend['ai'];
34
- modelRef: (slot: ModelSlot) => ModelRef;
34
+ modelRef: (slot: ModelRole) => ModelRef;
35
35
  }
36
- /** The suggestion source of the app behind `host`: `ai.complete` on the profile of the `complete` slot. */
36
+ /** The suggestion source of the app behind `host`: `ai.complete` on the profile of the `complete` Model role. */
37
37
  export declare function completionFetcher(host: CompletionHost): GhostAutocompleteOptions['fetchSuggestion'];
38
38
  /**
39
39
  * Inline AI autocomplete: after a typing pause at the end of a non-empty textblock, a short continuation is shown as grey
@@ -28,7 +28,7 @@ function mapSuggestion(suggestion, tr, oldState, newState) {
28
28
  pos: mapped.pos
29
29
  };
30
30
  }
31
- /** The suggestion source of the app behind `host`: `ai.complete` on the profile of the `complete` slot. */
31
+ /** The suggestion source of the app behind `host`: `ai.complete` on the profile of the `complete` Model role. */
32
32
  function completionFetcher(host) {
33
33
  return async (before, signal) => {
34
34
  if (!host.ai) return "";
@@ -1 +1 @@
1
- {"version":3,"file":"ghost-autocomplete.js","names":[],"sources":["../../../src/features/ai/ghost-autocomplete.ts"],"sourcesContent":["import { Extension } from '@tiptap/core'\nimport { type EditorState, Plugin, PluginKey, TextSelection, type Transaction } from '@tiptap/pm/state'\nimport { Decoration, DecorationSet, type EditorView } from '@tiptap/pm/view'\nimport type { Store } from '../../core/store'\nimport { anchorResolverOf, hasAbility } from '../../core'\nimport { ABILITY } from '../../core/schema'\nimport type { EditorSettings, ModelSlot } from '../../settings'\nimport type { EditorBackend } from '../../core/backend'\nimport { AI_COMPLETE_LIMITS, type ModelRef } from './protocol'\n\nexport interface GhostAutocompleteOptions {\n /** The app's shared settings: `ai.autocomplete` switches the suggestions on. */\n settings: Store<EditorSettings>\n /** Pause after the last keystroke before a suggestion is requested (ms). */\n debounce: number\n /** Fetches a continuation of `before` (document text up to the caret); '' for none. Must honour `signal`. */\n fetchSuggestion: (before: string, signal: AbortSignal) => Promise<string>\n}\n\ninterface Suggestion { text: string, pos: number }\ninterface GhostState {\n suggestion: Suggestion | null\n /** Bumped by local edits: each bump starts a new pause, so at most one request follows it. */\n edits: number\n /** Bumped by local edits and caret moves: an in-flight request is stale once this changed. */\n activity: number\n}\ntype GhostMeta = { type: 'show', suggestion: Suggestion } | { type: 'clear' }\n\nexport const ghostAutocompleteKey = new PluginKey<GhostState>('ghostAutocomplete')\n\n/** Text of the caret's textblock, when the caret is an empty selection at the end of a non-empty, non-code textblock. */\nfunction blockTextAtEnd(state: EditorState): string | null {\n const { selection } = state\n if (!(selection instanceof TextSelection) || !selection.empty) return null\n const { $head } = selection\n const block = $head.parent\n if (!block.isTextblock || block.type.spec.code || $head.parentOffset !== block.content.size) return null\n const text = block.textContent\n return text.trim() ? text : null\n}\n\n/** Keeps a suggestion across a collaborator's change only if the caret block is untouched and the caret stayed with it. */\nfunction mapSuggestion(suggestion: Suggestion, tr: Transaction, oldState: EditorState, newState: EditorState): Suggestion | null {\n const mapped = tr.mapping.mapResult(suggestion.pos)\n if (mapped.deleted || newState.selection.head !== mapped.pos) return null\n const text = blockTextAtEnd(newState)\n if (text === null || text !== oldState.doc.resolve(suggestion.pos).parent.textContent) return null\n return { text: suggestion.text, pos: mapped.pos }\n}\n\n/** What the suggestion source needs of the app: its AI port and the model profile of a slot (`useModelProfiles`). */\nexport interface CompletionHost {\n /** `EditorContext.backend.ai`; without it there are no suggestions. */\n ai: EditorBackend['ai']\n modelRef: (slot: ModelSlot) => ModelRef\n}\n\n/** The suggestion source of the app behind `host`: `ai.complete` on the profile of the `complete` slot. */\nexport function completionFetcher(host: CompletionHost): GhostAutocompleteOptions['fetchSuggestion'] {\n return async (before, signal) => {\n if (!host.ai) return ''\n const { text } = await host.ai.complete({ before, model: host.modelRef('complete') }, signal)\n return text\n }\n}\n\n/**\n * Inline AI autocomplete: after a typing pause at the end of a non-empty textblock, a short continuation is shown as grey\n * ghost text after the caret. Tab accepts it as normal text, Esc dismisses it; typing, caret moves and blur clear it.\n * The suggestion is a local widget decoration — never part of the document, so collaborators never see it.\n * On while the editor setting `ai.autocomplete` is (see `useEditorSettings`); turning it off clears the ghost.\n * Client-only: not part of `schemaExtensions()`.\n */\nexport const ghostAutocomplete = (options: GhostAutocompleteOptions) => Extension.create({\n name: 'ghostAutocomplete',\n // Runs its Tab/Escape bindings before ListItem's Tab (sinkListItem); both return false without a suggestion.\n priority: 1000,\n\n addKeyboardShortcuts() {\n return {\n Tab: ({ editor }) => {\n const suggestion = ghostAutocompleteKey.getState(editor.state)?.suggestion\n const { selection } = editor.state\n if (!suggestion || !selection.empty || selection.head !== suggestion.pos) return false\n const end = suggestion.pos + suggestion.text.length\n const tr = editor.state.tr.insertText(suggestion.text, suggestion.pos)\n editor.view.dispatch(tr.setSelection(TextSelection.create(tr.doc, end)).scrollIntoView())\n return true\n },\n Escape: ({ editor }) => {\n if (!ghostAutocompleteKey.getState(editor.state)?.suggestion) return false\n editor.view.dispatch(editor.state.tr.setMeta(ghostAutocompleteKey, { type: 'clear' } satisfies GhostMeta))\n return true\n },\n }\n },\n\n addProseMirrorPlugins() {\n const { editor } = this\n const { settings } = options\n let timer: number | undefined\n let inFlight: AbortController | null = null\n\n function cancel() {\n clearTimeout(timer)\n timer = undefined\n inFlight?.abort()\n inFlight = null\n }\n\n function eligible(view: EditorView): boolean {\n const { state } = view\n if (!settings.get().ai.autocomplete || !editor.isEditable || !view.hasFocus() || view.composing || blockTextAtEnd(state) === null) return false\n if (!hasAbility(editor, ABILITY.aiAutocomplete)) return false\n // No ghost while an @tiptap/suggestion popup (e.g. `@` mentions) is open: its state is `{ active, query, … }`.\n return !state.plugins.some((plugin) => {\n const pluginState: unknown = plugin.getState(state)\n return typeof pluginState === 'object' && pluginState !== null && 'query' in pluginState && 'active' in pluginState && pluginState.active === true\n })\n }\n\n async function request(view: EditorView, activity: number) {\n timer = undefined\n const { state } = view\n if (ghostAutocompleteKey.getState(state)?.activity !== activity || !eligible(view)) return\n const pos = state.selection.head\n const blockText = blockTextAtEnd(state)\n // Positions count at least one per character, so twice the limit in positions covers the character limit.\n const before = state.doc.textBetween(Math.max(0, pos - AI_COMPLETE_LIMITS.before * 2), pos, '\\n\\n').slice(-AI_COMPLETE_LIMITS.before)\n const controller = new AbortController()\n inFlight = controller\n let text: string\n try {\n text = await options.fetchSuggestion(before, controller.signal)\n } catch {\n // Aborted, rate-limited (429) or failed: autocomplete is a silent nicety, so no ghost and no toast.\n return\n } finally {\n if (inFlight === controller) inFlight = null\n }\n if (controller.signal.aborted || !text || view.isDestroyed) return\n // Stale-response guard: no local edit or caret move since the request, and the caret block text is unchanged\n // (a collaborator's change elsewhere may have shifted the caret position).\n const now = view.state\n if (ghostAutocompleteKey.getState(now)?.activity !== activity || !eligible(view) || blockTextAtEnd(now) !== blockText) return\n view.dispatch(now.tr.setMeta(ghostAutocompleteKey, { type: 'show', suggestion: { text, pos: now.selection.head } } satisfies GhostMeta))\n }\n\n return [\n new Plugin<GhostState>({\n key: ghostAutocompleteKey,\n state: {\n init: () => ({ suggestion: null, edits: 0, activity: 0 }),\n apply(tr, prev, oldState, newState) {\n const meta = tr.getMeta(ghostAutocompleteKey) as GhostMeta | undefined\n // A collaborator's edit (the collaboration feature's resolver tells); the user's own undo/redo is not remote.\n const remote = anchorResolverOf(editor)?.isRemoteChange(tr) ?? false\n const edited = tr.docChanged && !remote\n const moved = tr.selectionSet && !remote\n let suggestion = prev.suggestion\n if (meta?.type === 'show') suggestion = meta.suggestion\n else if (meta?.type === 'clear' || edited || moved) suggestion = null\n else if (suggestion && tr.docChanged) suggestion = mapSuggestion(suggestion, tr, oldState, newState)\n if (suggestion === prev.suggestion && !edited && !moved) return prev\n return { suggestion, edits: prev.edits + (edited ? 1 : 0), activity: prev.activity + (edited || moved ? 1 : 0) }\n },\n },\n props: {\n decorations(state) {\n const suggestion = ghostAutocompleteKey.getState(state)?.suggestion\n if (!suggestion) return null\n const widget = Decoration.widget(suggestion.pos, () => {\n const span = document.createElement('span')\n span.className = 'ghost-autocomplete'\n span.contentEditable = 'false'\n span.setAttribute('aria-hidden', 'true')\n span.textContent = suggestion.text\n return span\n }, { side: 1, key: `ghost:${suggestion.text}`, ignoreSelection: true })\n return DecorationSet.create(state.doc, [widget])\n },\n handleDOMEvents: {\n blur(view) {\n cancel()\n if (ghostAutocompleteKey.getState(view.state)?.suggestion) {\n view.dispatch(view.state.tr.setMeta(ghostAutocompleteKey, { type: 'clear' } satisfies GhostMeta))\n }\n return false\n },\n },\n },\n view: (view) => {\n // Turned off (toolbar or settings): drop the pending request and the shown ghost right away.\n let last = settings.get().ai.autocomplete\n const stop = settings.subscribe((value) => {\n const enabled = value.ai.autocomplete\n if (enabled === last) return\n last = enabled\n if (enabled || view.isDestroyed) return\n cancel()\n if (ghostAutocompleteKey.getState(view.state)?.suggestion) {\n view.dispatch(view.state.tr.setMeta(ghostAutocompleteKey, { type: 'clear' } satisfies GhostMeta))\n }\n })\n return {\n update(view, prevState) {\n const next = ghostAutocompleteKey.getState(view.state)\n const prev = ghostAutocompleteKey.getState(prevState)\n if (!next || !prev) return\n if (!settings.get().ai.autocomplete) return cancel()\n if (next.activity === prev.activity) return\n // Typing or a caret move: drop the pending pause and abort the in-flight request.\n cancel()\n // Only a local edit starts a new pause; caret moves alone never request.\n if (next.edits === prev.edits || !eligible(view)) return\n const activity = next.activity\n timer = window.setTimeout(() => void request(view, activity), options.debounce)\n },\n destroy() {\n stop()\n cancel()\n },\n }\n },\n }),\n ]\n },\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"ghost-autocomplete.js","names":[],"sources":["../../../src/features/ai/ghost-autocomplete.ts"],"sourcesContent":["import { Extension } from '@tiptap/core'\nimport { type EditorState, Plugin, PluginKey, TextSelection, type Transaction } from '@tiptap/pm/state'\nimport { Decoration, DecorationSet, type EditorView } from '@tiptap/pm/view'\nimport type { Store } from '../../core/store'\nimport { anchorResolverOf, hasAbility } from '../../core'\nimport { ABILITY } from '../../core/schema'\nimport type { EditorSettings, ModelRole } from '../../settings'\nimport type { EditorBackend } from '../../core/backend'\nimport { AI_COMPLETE_LIMITS, type ModelRef } from './protocol'\n\nexport interface GhostAutocompleteOptions {\n /** The app's shared settings: `ai.autocomplete` switches the suggestions on. */\n settings: Store<EditorSettings>\n /** Pause after the last keystroke before a suggestion is requested (ms). */\n debounce: number\n /** Fetches a continuation of `before` (document text up to the caret); '' for none. Must honour `signal`. */\n fetchSuggestion: (before: string, signal: AbortSignal) => Promise<string>\n}\n\ninterface Suggestion { text: string, pos: number }\ninterface GhostState {\n suggestion: Suggestion | null\n /** Bumped by local edits: each bump starts a new pause, so at most one request follows it. */\n edits: number\n /** Bumped by local edits and caret moves: an in-flight request is stale once this changed. */\n activity: number\n}\ntype GhostMeta = { type: 'show', suggestion: Suggestion } | { type: 'clear' }\n\nexport const ghostAutocompleteKey = new PluginKey<GhostState>('ghostAutocomplete')\n\n/** Text of the caret's textblock, when the caret is an empty selection at the end of a non-empty, non-code textblock. */\nfunction blockTextAtEnd(state: EditorState): string | null {\n const { selection } = state\n if (!(selection instanceof TextSelection) || !selection.empty) return null\n const { $head } = selection\n const block = $head.parent\n if (!block.isTextblock || block.type.spec.code || $head.parentOffset !== block.content.size) return null\n const text = block.textContent\n return text.trim() ? text : null\n}\n\n/** Keeps a suggestion across a collaborator's change only if the caret block is untouched and the caret stayed with it. */\nfunction mapSuggestion(suggestion: Suggestion, tr: Transaction, oldState: EditorState, newState: EditorState): Suggestion | null {\n const mapped = tr.mapping.mapResult(suggestion.pos)\n if (mapped.deleted || newState.selection.head !== mapped.pos) return null\n const text = blockTextAtEnd(newState)\n if (text === null || text !== oldState.doc.resolve(suggestion.pos).parent.textContent) return null\n return { text: suggestion.text, pos: mapped.pos }\n}\n\n/** What the suggestion source needs of the app: its AI port and the model profile of a Model role (`useModelProfiles`). */\nexport interface CompletionHost {\n /** `EditorContext.backend.ai`; without it there are no suggestions. */\n ai: EditorBackend['ai']\n modelRef: (slot: ModelRole) => ModelRef\n}\n\n/** The suggestion source of the app behind `host`: `ai.complete` on the profile of the `complete` Model role. */\nexport function completionFetcher(host: CompletionHost): GhostAutocompleteOptions['fetchSuggestion'] {\n return async (before, signal) => {\n if (!host.ai) return ''\n const { text } = await host.ai.complete({ before, model: host.modelRef('complete') }, signal)\n return text\n }\n}\n\n/**\n * Inline AI autocomplete: after a typing pause at the end of a non-empty textblock, a short continuation is shown as grey\n * ghost text after the caret. Tab accepts it as normal text, Esc dismisses it; typing, caret moves and blur clear it.\n * The suggestion is a local widget decoration — never part of the document, so collaborators never see it.\n * On while the editor setting `ai.autocomplete` is (see `useEditorSettings`); turning it off clears the ghost.\n * Client-only: not part of `schemaExtensions()`.\n */\nexport const ghostAutocomplete = (options: GhostAutocompleteOptions) => Extension.create({\n name: 'ghostAutocomplete',\n // Runs its Tab/Escape bindings before ListItem's Tab (sinkListItem); both return false without a suggestion.\n priority: 1000,\n\n addKeyboardShortcuts() {\n return {\n Tab: ({ editor }) => {\n const suggestion = ghostAutocompleteKey.getState(editor.state)?.suggestion\n const { selection } = editor.state\n if (!suggestion || !selection.empty || selection.head !== suggestion.pos) return false\n const end = suggestion.pos + suggestion.text.length\n const tr = editor.state.tr.insertText(suggestion.text, suggestion.pos)\n editor.view.dispatch(tr.setSelection(TextSelection.create(tr.doc, end)).scrollIntoView())\n return true\n },\n Escape: ({ editor }) => {\n if (!ghostAutocompleteKey.getState(editor.state)?.suggestion) return false\n editor.view.dispatch(editor.state.tr.setMeta(ghostAutocompleteKey, { type: 'clear' } satisfies GhostMeta))\n return true\n },\n }\n },\n\n addProseMirrorPlugins() {\n const { editor } = this\n const { settings } = options\n let timer: number | undefined\n let inFlight: AbortController | null = null\n\n function cancel() {\n clearTimeout(timer)\n timer = undefined\n inFlight?.abort()\n inFlight = null\n }\n\n function eligible(view: EditorView): boolean {\n const { state } = view\n if (!settings.get().ai.autocomplete || !editor.isEditable || !view.hasFocus() || view.composing || blockTextAtEnd(state) === null) return false\n if (!hasAbility(editor, ABILITY.aiAutocomplete)) return false\n // No ghost while an @tiptap/suggestion popup (e.g. `@` mentions) is open: its state is `{ active, query, … }`.\n return !state.plugins.some((plugin) => {\n const pluginState: unknown = plugin.getState(state)\n return typeof pluginState === 'object' && pluginState !== null && 'query' in pluginState && 'active' in pluginState && pluginState.active === true\n })\n }\n\n async function request(view: EditorView, activity: number) {\n timer = undefined\n const { state } = view\n if (ghostAutocompleteKey.getState(state)?.activity !== activity || !eligible(view)) return\n const pos = state.selection.head\n const blockText = blockTextAtEnd(state)\n // Positions count at least one per character, so twice the limit in positions covers the character limit.\n const before = state.doc.textBetween(Math.max(0, pos - AI_COMPLETE_LIMITS.before * 2), pos, '\\n\\n').slice(-AI_COMPLETE_LIMITS.before)\n const controller = new AbortController()\n inFlight = controller\n let text: string\n try {\n text = await options.fetchSuggestion(before, controller.signal)\n } catch {\n // Aborted, rate-limited (429) or failed: autocomplete is a silent nicety, so no ghost and no toast.\n return\n } finally {\n if (inFlight === controller) inFlight = null\n }\n if (controller.signal.aborted || !text || view.isDestroyed) return\n // Stale-response guard: no local edit or caret move since the request, and the caret block text is unchanged\n // (a collaborator's change elsewhere may have shifted the caret position).\n const now = view.state\n if (ghostAutocompleteKey.getState(now)?.activity !== activity || !eligible(view) || blockTextAtEnd(now) !== blockText) return\n view.dispatch(now.tr.setMeta(ghostAutocompleteKey, { type: 'show', suggestion: { text, pos: now.selection.head } } satisfies GhostMeta))\n }\n\n return [\n new Plugin<GhostState>({\n key: ghostAutocompleteKey,\n state: {\n init: () => ({ suggestion: null, edits: 0, activity: 0 }),\n apply(tr, prev, oldState, newState) {\n const meta = tr.getMeta(ghostAutocompleteKey) as GhostMeta | undefined\n // A collaborator's edit (the collaboration feature's resolver tells); the user's own undo/redo is not remote.\n const remote = anchorResolverOf(editor)?.isRemoteChange(tr) ?? false\n const edited = tr.docChanged && !remote\n const moved = tr.selectionSet && !remote\n let suggestion = prev.suggestion\n if (meta?.type === 'show') suggestion = meta.suggestion\n else if (meta?.type === 'clear' || edited || moved) suggestion = null\n else if (suggestion && tr.docChanged) suggestion = mapSuggestion(suggestion, tr, oldState, newState)\n if (suggestion === prev.suggestion && !edited && !moved) return prev\n return { suggestion, edits: prev.edits + (edited ? 1 : 0), activity: prev.activity + (edited || moved ? 1 : 0) }\n },\n },\n props: {\n decorations(state) {\n const suggestion = ghostAutocompleteKey.getState(state)?.suggestion\n if (!suggestion) return null\n const widget = Decoration.widget(suggestion.pos, () => {\n const span = document.createElement('span')\n span.className = 'ghost-autocomplete'\n span.contentEditable = 'false'\n span.setAttribute('aria-hidden', 'true')\n span.textContent = suggestion.text\n return span\n }, { side: 1, key: `ghost:${suggestion.text}`, ignoreSelection: true })\n return DecorationSet.create(state.doc, [widget])\n },\n handleDOMEvents: {\n blur(view) {\n cancel()\n if (ghostAutocompleteKey.getState(view.state)?.suggestion) {\n view.dispatch(view.state.tr.setMeta(ghostAutocompleteKey, { type: 'clear' } satisfies GhostMeta))\n }\n return false\n },\n },\n },\n view: (view) => {\n // Turned off (toolbar or settings): drop the pending request and the shown ghost right away.\n let last = settings.get().ai.autocomplete\n const stop = settings.subscribe((value) => {\n const enabled = value.ai.autocomplete\n if (enabled === last) return\n last = enabled\n if (enabled || view.isDestroyed) return\n cancel()\n if (ghostAutocompleteKey.getState(view.state)?.suggestion) {\n view.dispatch(view.state.tr.setMeta(ghostAutocompleteKey, { type: 'clear' } satisfies GhostMeta))\n }\n })\n return {\n update(view, prevState) {\n const next = ghostAutocompleteKey.getState(view.state)\n const prev = ghostAutocompleteKey.getState(prevState)\n if (!next || !prev) return\n if (!settings.get().ai.autocomplete) return cancel()\n if (next.activity === prev.activity) return\n // Typing or a caret move: drop the pending pause and abort the in-flight request.\n cancel()\n // Only a local edit starts a new pause; caret moves alone never request.\n if (next.edits === prev.edits || !eligible(view)) return\n const activity = next.activity\n timer = window.setTimeout(() => void request(view, activity), options.debounce)\n },\n destroy() {\n stop()\n cancel()\n },\n }\n },\n }),\n ]\n },\n})\n"],"mappings":"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"}
@@ -1,11 +1,11 @@
1
1
  import { ModelProfile, ModelRef } from "../../core/backend-types.js";
2
2
  import { BLOCK_LINES_LABEL, BLOCK_LINE_COMPOSITE_TEXT, BLOCK_LINE_ECHO_TEXT, BLOCK_LINE_EXAMPLE, BLOCK_LINE_EXAMPLE_ID, BLOCK_LINE_EXAMPLE_TEXT, BLOCK_LINE_HOST_TEXT, BLOCK_LINE_IDS_HINT, BLOCK_LINE_INTRO, BLOCK_LINE_LIST_TEXT, BLOCK_LINE_MARKERS, BlockLines, TRUNCATED_LINE, blockLine, compositeChromePart, compositeLineClose, compositeLineHeader, continuedLinePrefix, listLinePrefix, nestedLinePrefix, quoteLinePrefix, readBlockLines, singleBlockLine, stripBlockLineEcho, stripListMarkerEcho } from "./protocol/block-lines.js";
3
3
  import { AGENT_LIMITS, AGENT_OP_OUTCOMES, AGENT_OP_OUTCOME_TEXT, AGENT_OP_TYPES, AGENT_TOOL, AgentOp, AgentOpContext, AgentOpFeedback, AgentOpOutcome, AgentOpProblem, AgentOpProblemReason, AgentOpType, AgentTextOptions, ModelAgentOp, agentFeedbackText, agentOpSummary, agentOpTarget, agentRetryMessage, agentShownMessage, agentUnreadableProblem, checkAgentOps } from "./protocol/agent-ops.js";
4
- import { CHAT_LIMITS, CITATION_HREF_PREFIX, ChatBlock, ChatBlockModel, ChatCompositeKind, DocumentChatMessage, citationBlockId, documentChatMessages } from "./protocol/chat.js";
4
+ import { CHAT_LIMITS, CITATION_HREF_PREFIX, ChatBlock, ChatBlockModel, ChatBlockType, DocumentChatMessage, citationBlockId, documentChatMessages } from "./protocol/chat.js";
5
5
  import { AI_LIMITS, AI_TASKS, AI_TASK_IDS, AiApplyMode, AiBlockInput, AiInput, AiMessage, AiTask, AiTaskId, blockTasks, inBlockTasks, withHeading, withTaskHeading } from "./protocol/tasks.js";
6
6
  import { ChatMessage, ChatStream, GenerateInput, generateBodySchema, generateProblem, runGenerate } from "./protocol/generate.js";
7
7
  import { AI_COMPLETE_LIMITS, AiCompleteMessage, cleanCompletion, completeBodySchema, completeMessages, completionReady, runCompletion } from "./protocol/complete.js";
8
- import { AI_LANGUAGE_KEYS, MODEL_REF_LIMITS, MODEL_SLOT_KEYS, UserModelProfile, modelRefSchema } from "./protocol/models.js";
8
+ import { AI_LANGUAGE_KEYS, MODEL_REF_LIMITS, MODEL_ROLE_KEYS, UserModelProfile, modelRefSchema } from "./protocol/models.js";
9
9
  import { AI_ID_PATTERN, aiBlockInputSchema, aiBlockSchema } from "./protocol/schemas.js";
10
10
  import "./protocol/index.js";
11
11
  import { AiReview, AiReviewChange, AiReviewChangeSummary, AiReviewDecision, AiReviewHandle, AiReviewHunk, AiReviewOptions, AiReviewOutcome, AiReviewSkipReason, AiReviewState, acceptAiReview, aiReviewKey, rejectAiReview, setActiveAiReviewHunk, startAiReview } from "./ai-review.js";
@@ -25,4 +25,4 @@ import { ModelProfilesModel, modelProfiles } from "./model-profiles.js";
25
25
  import { isRateLimited, notifyAiRateLimited } from "./rate-limit.js";
26
26
  import { AiSidebarFlow, AiSidebarFlowOptions, createAiSidebarFlow } from "./sidebar-flow.js";
27
27
  import { AI_SELECTION_MENU_KEY, AiSelectionFlow, AiSelectionFlowOptions, AiSelectionMode, AiSelectionRequest, AiSelectionState, createAiSelectionFlow } from "./selection-flow.js";
28
- export { AGENT_LIMITS, AGENT_OP_OUTCOMES, AGENT_OP_OUTCOME_TEXT, AGENT_OP_TYPES, AGENT_TOOL, AI_COMPLETE_LIMITS, AI_ID_PATTERN, AI_LANGUAGE_KEYS, AI_LIMITS, AI_MENU_AT_CARET, AI_MENU_FOR_SELECTION, AI_SELECTION_MENU_KEY, AI_TASKS, AI_TASK_IDS, AgentOp, AgentOpContext, AgentOpFeedback, AgentOpOutcome, AgentOpProblem, AgentOpProblemReason, type AgentOpReview, type AgentOpReviewOptions, type AgentOpReviewState, type AgentOpState, AgentOpType, type AgentScope, AgentTextOptions, AiApplyMode, type AiApplyOutcome, type AiAssistant, type AiAssistantOptions, type AiAssistantState, AiBlockInput, AiCompleteMessage, AiInput, type AiMenuAction, AiMessage, type AiResultAction, AiReview, type AiReviewChange, type AiReviewChangeSummary, type AiReviewDecision, type AiReviewHandle, type AiReviewHunk, type AiReviewOptions, type AiReviewOutcome, type AiReviewSkipReason, type AiReviewState, type AiRunBody, type AiSelectionFlow, type AiSelectionFlowOptions, AiSelectionHighlight, type AiSelectionMode, type AiSelectionRequest, type AiSelectionState, type AiSidebarFlow, type AiSidebarFlowOptions, type AiSseOutcome, type AiStatus, type AiTarget, AiTask, AiTaskId, type AiUi, BLOCK_LINES_LABEL, BLOCK_LINE_COMPOSITE_TEXT, BLOCK_LINE_ECHO_TEXT, BLOCK_LINE_EXAMPLE, BLOCK_LINE_EXAMPLE_ID, BLOCK_LINE_EXAMPLE_TEXT, BLOCK_LINE_HOST_TEXT, BLOCK_LINE_IDS_HINT, BLOCK_LINE_INTRO, BLOCK_LINE_LIST_TEXT, BLOCK_LINE_MARKERS, BlockLines, CHAT_LIMITS, CITATION_HREF_PREFIX, ChatBlock, ChatBlockModel, ChatCompositeKind, ChatMessage, ChatStream, type DocumentChat, type DocumentChatGeneration, DocumentChatMessage, type DocumentChatOptions, type DocumentChatState, type DocumentChatTurn, GenerateInput, type GhostAutocompleteOptions, MODEL_REF_LIMITS, MODEL_SLOT_KEYS, ModelAgentOp, type ModelProfile, type ModelProfilesModel, type ModelRef, TRUNCATED_LINE, UserModelProfile, acceptAiReview, agentFeedbackText, agentOpSummary, agentOpTarget, agentRetryMessage, agentShownMessage, agentUnreadableProblem, aiApplyFailure, aiBlockAction, aiBlockInputSchema, aiBlockSchema, aiCommand, aiFeatureCore, aiMenuActionsOf, aiReviewKey, aiSelectionHighlightKey, applyAiResult, blockLine, blockTasks, blockTextRange, captureTarget, checkAgentOps, citationBlockId, cleanCompletion, completeBodySchema, completeMessages, completionFetcher, completionReady, compositeChromePart, compositeLineClose, compositeLineHeader, continuedLinePrefix, createAgentOpReview, createAiAssistant, createAiSelectionFlow, createAiSidebarFlow, createDocumentChat, documentChatMessages, documentChatText, documentMarkdown, formatTaskResult, generateBodySchema, generateProblem, ghostAutocomplete, ghostAutocompleteKey, hideAiSelectionHighlight, inBlockTasks, insertAtCaretLine, insertBlocksAtTarget, insertBlocksBelow, isRateLimited, listLinePrefix, modelProfiles, modelRefSchema, nestedLinePrefix, notifyAiRateLimited, openAiMenuAtCaret, openAiMenuForSelection, postAiSse, quoteLinePrefix, rangeMarkdown, readBlockLines, rejectAiReview, resultBlocks, runCompletion, runGenerate, selectionMarkdown, selectionScope, setActiveAiReviewHunk, showAiSelectionHighlight, singleBlockLine, startAiReview, stripBlockLineEcho, stripListMarkerEcho, withHeading, withTaskHeading };
28
+ export { AGENT_LIMITS, AGENT_OP_OUTCOMES, AGENT_OP_OUTCOME_TEXT, AGENT_OP_TYPES, AGENT_TOOL, AI_COMPLETE_LIMITS, AI_ID_PATTERN, AI_LANGUAGE_KEYS, AI_LIMITS, AI_MENU_AT_CARET, AI_MENU_FOR_SELECTION, AI_SELECTION_MENU_KEY, AI_TASKS, AI_TASK_IDS, AgentOp, AgentOpContext, AgentOpFeedback, AgentOpOutcome, AgentOpProblem, AgentOpProblemReason, type AgentOpReview, type AgentOpReviewOptions, type AgentOpReviewState, type AgentOpState, AgentOpType, type AgentScope, AgentTextOptions, AiApplyMode, type AiApplyOutcome, type AiAssistant, type AiAssistantOptions, type AiAssistantState, AiBlockInput, AiCompleteMessage, AiInput, type AiMenuAction, AiMessage, type AiResultAction, AiReview, type AiReviewChange, type AiReviewChangeSummary, type AiReviewDecision, type AiReviewHandle, type AiReviewHunk, type AiReviewOptions, type AiReviewOutcome, type AiReviewSkipReason, type AiReviewState, type AiRunBody, type AiSelectionFlow, type AiSelectionFlowOptions, AiSelectionHighlight, type AiSelectionMode, type AiSelectionRequest, type AiSelectionState, type AiSidebarFlow, type AiSidebarFlowOptions, type AiSseOutcome, type AiStatus, type AiTarget, AiTask, AiTaskId, type AiUi, BLOCK_LINES_LABEL, BLOCK_LINE_COMPOSITE_TEXT, BLOCK_LINE_ECHO_TEXT, BLOCK_LINE_EXAMPLE, BLOCK_LINE_EXAMPLE_ID, BLOCK_LINE_EXAMPLE_TEXT, BLOCK_LINE_HOST_TEXT, BLOCK_LINE_IDS_HINT, BLOCK_LINE_INTRO, BLOCK_LINE_LIST_TEXT, BLOCK_LINE_MARKERS, BlockLines, CHAT_LIMITS, CITATION_HREF_PREFIX, ChatBlock, ChatBlockModel, ChatBlockType, ChatMessage, ChatStream, type DocumentChat, type DocumentChatGeneration, DocumentChatMessage, type DocumentChatOptions, type DocumentChatState, type DocumentChatTurn, GenerateInput, type GhostAutocompleteOptions, MODEL_REF_LIMITS, MODEL_ROLE_KEYS, ModelAgentOp, type ModelProfile, type ModelProfilesModel, type ModelRef, TRUNCATED_LINE, UserModelProfile, acceptAiReview, agentFeedbackText, agentOpSummary, agentOpTarget, agentRetryMessage, agentShownMessage, agentUnreadableProblem, aiApplyFailure, aiBlockAction, aiBlockInputSchema, aiBlockSchema, aiCommand, aiFeatureCore, aiMenuActionsOf, aiReviewKey, aiSelectionHighlightKey, applyAiResult, blockLine, blockTasks, blockTextRange, captureTarget, checkAgentOps, citationBlockId, cleanCompletion, completeBodySchema, completeMessages, completionFetcher, completionReady, compositeChromePart, compositeLineClose, compositeLineHeader, continuedLinePrefix, createAgentOpReview, createAiAssistant, createAiSelectionFlow, createAiSidebarFlow, createDocumentChat, documentChatMessages, documentChatText, documentMarkdown, formatTaskResult, generateBodySchema, generateProblem, ghostAutocomplete, ghostAutocompleteKey, hideAiSelectionHighlight, inBlockTasks, insertAtCaretLine, insertBlocksAtTarget, insertBlocksBelow, isRateLimited, listLinePrefix, modelProfiles, modelRefSchema, nestedLinePrefix, notifyAiRateLimited, openAiMenuAtCaret, openAiMenuForSelection, postAiSse, quoteLinePrefix, rangeMarkdown, readBlockLines, rejectAiReview, resultBlocks, runCompletion, runGenerate, selectionMarkdown, selectionScope, setActiveAiReviewHunk, showAiSelectionHighlight, singleBlockLine, startAiReview, stripBlockLineEcho, stripListMarkerEcho, withHeading, withTaskHeading };
@@ -1,4 +1,4 @@
1
- import { AI_LANGUAGE_KEYS, MODEL_REF_LIMITS, MODEL_SLOT_KEYS, modelRefSchema } from "./protocol/models.js";
1
+ import { AI_LANGUAGE_KEYS, MODEL_REF_LIMITS, MODEL_ROLE_KEYS, modelRefSchema } from "./protocol/models.js";
2
2
  import { AI_COMPLETE_LIMITS, cleanCompletion, completeBodySchema, completeMessages, completionReady, runCompletion } from "./protocol/complete.js";
3
3
  import { AI_LIMITS, AI_TASKS, AI_TASK_IDS, blockTasks, inBlockTasks, withHeading, withTaskHeading } from "./protocol/tasks.js";
4
4
  import { AI_ID_PATTERN, aiBlockInputSchema, aiBlockSchema } from "./protocol/schemas.js";
@@ -23,4 +23,4 @@ import { createAiSidebarFlow } from "./sidebar-flow.js";
23
23
  import { documentChatText } from "./document-chat.js";
24
24
  import { createAgentOpReview } from "./agent-op-review.js";
25
25
  import { createDocumentChat } from "./document-chat-model.js";
26
- export { AGENT_LIMITS, AGENT_OP_OUTCOMES, AGENT_OP_OUTCOME_TEXT, AGENT_OP_TYPES, AGENT_TOOL, AI_COMPLETE_LIMITS, AI_ID_PATTERN, AI_LANGUAGE_KEYS, AI_LIMITS, AI_MENU_AT_CARET, AI_MENU_FOR_SELECTION, AI_SELECTION_MENU_KEY, AI_TASKS, AI_TASK_IDS, AiReview, AiSelectionHighlight, BLOCK_LINES_LABEL, BLOCK_LINE_COMPOSITE_TEXT, BLOCK_LINE_ECHO_TEXT, BLOCK_LINE_EXAMPLE, BLOCK_LINE_EXAMPLE_ID, BLOCK_LINE_EXAMPLE_TEXT, BLOCK_LINE_HOST_TEXT, BLOCK_LINE_IDS_HINT, BLOCK_LINE_INTRO, BLOCK_LINE_LIST_TEXT, BLOCK_LINE_MARKERS, CHAT_LIMITS, CITATION_HREF_PREFIX, MODEL_REF_LIMITS, MODEL_SLOT_KEYS, TRUNCATED_LINE, acceptAiReview, agentFeedbackText, agentOpSummary, agentOpTarget, agentRetryMessage, agentShownMessage, agentUnreadableProblem, aiApplyFailure, aiBlockAction, aiBlockInputSchema, aiBlockSchema, aiCommand, aiFeatureCore, aiMenuActionsOf, aiReviewKey, aiSelectionHighlightKey, applyAiResult, blockLine, blockTasks, blockTextRange, captureTarget, checkAgentOps, citationBlockId, cleanCompletion, completeBodySchema, completeMessages, completionFetcher, completionReady, compositeChromePart, compositeLineClose, compositeLineHeader, continuedLinePrefix, createAgentOpReview, createAiAssistant, createAiSelectionFlow, createAiSidebarFlow, createDocumentChat, documentChatMessages, documentChatText, documentMarkdown, formatTaskResult, generateBodySchema, generateProblem, ghostAutocomplete, ghostAutocompleteKey, hideAiSelectionHighlight, inBlockTasks, insertAtCaretLine, insertBlocksAtTarget, insertBlocksBelow, isRateLimited, listLinePrefix, modelProfiles, modelRefSchema, nestedLinePrefix, notifyAiRateLimited, openAiMenuAtCaret, openAiMenuForSelection, postAiSse, quoteLinePrefix, rangeMarkdown, readBlockLines, rejectAiReview, resultBlocks, runCompletion, runGenerate, selectionMarkdown, selectionScope, setActiveAiReviewHunk, showAiSelectionHighlight, singleBlockLine, startAiReview, stripBlockLineEcho, stripListMarkerEcho, withHeading, withTaskHeading };
26
+ export { AGENT_LIMITS, AGENT_OP_OUTCOMES, AGENT_OP_OUTCOME_TEXT, AGENT_OP_TYPES, AGENT_TOOL, AI_COMPLETE_LIMITS, AI_ID_PATTERN, AI_LANGUAGE_KEYS, AI_LIMITS, AI_MENU_AT_CARET, AI_MENU_FOR_SELECTION, AI_SELECTION_MENU_KEY, AI_TASKS, AI_TASK_IDS, AiReview, AiSelectionHighlight, BLOCK_LINES_LABEL, BLOCK_LINE_COMPOSITE_TEXT, BLOCK_LINE_ECHO_TEXT, BLOCK_LINE_EXAMPLE, BLOCK_LINE_EXAMPLE_ID, BLOCK_LINE_EXAMPLE_TEXT, BLOCK_LINE_HOST_TEXT, BLOCK_LINE_IDS_HINT, BLOCK_LINE_INTRO, BLOCK_LINE_LIST_TEXT, BLOCK_LINE_MARKERS, CHAT_LIMITS, CITATION_HREF_PREFIX, MODEL_REF_LIMITS, MODEL_ROLE_KEYS, TRUNCATED_LINE, acceptAiReview, agentFeedbackText, agentOpSummary, agentOpTarget, agentRetryMessage, agentShownMessage, agentUnreadableProblem, aiApplyFailure, aiBlockAction, aiBlockInputSchema, aiBlockSchema, aiCommand, aiFeatureCore, aiMenuActionsOf, aiReviewKey, aiSelectionHighlightKey, applyAiResult, blockLine, blockTasks, blockTextRange, captureTarget, checkAgentOps, citationBlockId, cleanCompletion, completeBodySchema, completeMessages, completionFetcher, completionReady, compositeChromePart, compositeLineClose, compositeLineHeader, continuedLinePrefix, createAgentOpReview, createAiAssistant, createAiSelectionFlow, createAiSidebarFlow, createDocumentChat, documentChatMessages, documentChatText, documentMarkdown, formatTaskResult, generateBodySchema, generateProblem, ghostAutocomplete, ghostAutocompleteKey, hideAiSelectionHighlight, inBlockTasks, insertAtCaretLine, insertBlocksAtTarget, insertBlocksBelow, isRateLimited, listLinePrefix, modelProfiles, modelRefSchema, nestedLinePrefix, notifyAiRateLimited, openAiMenuAtCaret, openAiMenuForSelection, postAiSse, quoteLinePrefix, rangeMarkdown, readBlockLines, rejectAiReview, resultBlocks, runCompletion, runGenerate, selectionMarkdown, selectionScope, setActiveAiReviewHunk, showAiSelectionHighlight, singleBlockLine, startAiReview, stripBlockLineEcho, stripListMarkerEcho, withHeading, withTaskHeading };
@@ -1,5 +1,5 @@
1
1
  import { ReadonlyStore, Store } from "../../core/store.js";
2
- import { ModelSlot } from "../../settings/values.js";
2
+ import { ModelRole } from "../../settings/values.js";
3
3
  import "../../settings/index.js";
4
4
  import { EditorContext } from "../../core/context.js";
5
5
  import { ModelProfile, ModelRef } from "../../core/backend-types.js";
@@ -15,22 +15,22 @@ export interface ModelProfilesModel {
15
15
  /** Presets, then user profiles. Reads the stores: call it again after either changed. */
16
16
  profiles: () => ModelProfile[];
17
17
  /**
18
- * Profile a slot runs on: the one the settings assign to it, else the server's default preset for the slot, else the
19
- * first preset; none before the presets loaded (unless the settings point at a user profile).
18
+ * Profile a Model role runs on: the one the settings assign to it, else the server's default Model preset for the Model role, else the
19
+ * first Model preset; none before the Model presets loaded (unless the settings point at a user profile).
20
20
  */
21
- slotProfile: (slot: ModelSlot) => ModelProfile | undefined;
22
- /** What AI requests send as `model`; works before the presets loaded (the default slot preset of `createEditor({ ai })`). */
23
- modelRef: (slot: ModelSlot) => ModelRef;
21
+ slotProfile: (slot: ModelRole) => ModelProfile | undefined;
22
+ /** What AI requests send as `model`; works before the Model presets loaded (the default Model preset of the role of `createEditor({ ai })`). */
23
+ modelRef: (slot: ModelRole) => ModelRef;
24
24
  saveUserProfile: (profile: UserModelProfile) => void;
25
- /** Also resets every slot that ran on the profile to the server default. */
25
+ /** Also resets every Model role that ran on the profile to the server default. */
26
26
  removeUserProfile: (id: string) => void;
27
27
  }
28
28
  /**
29
29
  * Model profiles the AI features run on, shared by all editors of the app (cached per `createEditorContext`, never
30
- * process-global): server presets (`backend.ai.models()`, requested once on first
30
+ * process-global): Model presets (`backend.ai.models()`, requested once on first
31
31
  * use, without keys) plus user profiles that live only in this browser's localStorage (their key goes with each
32
32
  * request). Framework-free: `modelRef(slot)` is what AI requests send as `model`. Frameworks observe `presets`,
33
- * `userProfiles` and `app.settings` (the slot assignment is `settings.ai.slots`).
33
+ * `userProfiles` and `app.settings` (the Model role assignment is `settings.ai.roles`).
34
34
  */
35
35
  export declare function modelProfiles(app: EditorContext): ModelProfilesModel;
36
36
  //#endregion
@@ -1,4 +1,4 @@
1
- import { MODEL_SLOTS } from "../../settings/values.js";
1
+ import { MODEL_ROLES } from "../../settings/values.js";
2
2
  import { createStore } from "../../core/store.js";
3
3
  import { z } from "zod";
4
4
  //#region src/features/ai/model-profiles.ts
@@ -28,15 +28,15 @@ function loadUserProfiles() {
28
28
  function createModelProfiles(app) {
29
29
  const presets = createStore([]);
30
30
  const userProfiles = createStore(loadUserProfiles());
31
- /** Default preset id per slot as the server reports it; until then the app's public AI configuration. */
32
- let serverSlots = null;
33
- const defaultSlots = app.ai?.slots ?? {
31
+ /** Default Model preset id per Model role as the server reports it; until then the app's public AI configuration. */
32
+ let serverRoles = null;
33
+ const defaultRoles = app.ai?.roles ?? {
34
34
  complete: "",
35
35
  rewrite: "",
36
36
  generate: ""
37
37
  };
38
38
  app.backend.ai?.models().then((response) => {
39
- serverSlots = response.slots;
39
+ serverRoles = response.roles;
40
40
  presets.set(response.presets);
41
41
  }).catch((error) => {
42
42
  console.warn("tiptap-editor: Modell-Presets konnten nicht geladen werden", error);
@@ -49,13 +49,13 @@ function createModelProfiles(app) {
49
49
  source: "user"
50
50
  }))];
51
51
  const slotProfile = (slot) => {
52
- const chosen = app.settings.get().ai.slots[slot];
53
- const defaultId = (serverSlots ?? defaultSlots)[slot];
52
+ const chosen = app.settings.get().ai.roles[slot];
53
+ const defaultId = (serverRoles ?? defaultRoles)[slot];
54
54
  return profiles().find((p) => p.id === chosen) ?? presets.get().find((p) => p.id === defaultId) ?? presets.get()[0];
55
55
  };
56
56
  const modelRef = (slot) => {
57
57
  const profile = slotProfile(slot);
58
- if (!profile) return { preset: (serverSlots ?? defaultSlots)[slot] };
58
+ if (!profile) return { preset: (serverRoles ?? defaultRoles)[slot] };
59
59
  const user = profile.source === "user" ? userProfiles.get().find((p) => p.id === profile.id) : void 0;
60
60
  return user ? {
61
61
  endpoint: user.endpoint,
@@ -74,9 +74,9 @@ function createModelProfiles(app) {
74
74
  const next = userProfiles.get().filter((p) => p.id !== id);
75
75
  userProfiles.set(next);
76
76
  storeUserProfiles(next);
77
- const slots = app.settings.get().ai.slots;
78
- if (MODEL_SLOTS.some((slot) => slots[slot] === id)) app.settings.update((s) => {
79
- for (const slot of MODEL_SLOTS) if (s.ai.slots[slot] === id) delete s.ai.slots[slot];
77
+ const roles = app.settings.get().ai.roles;
78
+ if (MODEL_ROLES.some((slot) => roles[slot] === id)) app.settings.update((s) => {
79
+ for (const slot of MODEL_ROLES) if (s.ai.roles[slot] === id) delete s.ai.roles[slot];
80
80
  });
81
81
  };
82
82
  return {
@@ -92,10 +92,10 @@ function createModelProfiles(app) {
92
92
  const models = /* @__PURE__ */ new WeakMap();
93
93
  /**
94
94
  * Model profiles the AI features run on, shared by all editors of the app (cached per `createEditorContext`, never
95
- * process-global): server presets (`backend.ai.models()`, requested once on first
95
+ * process-global): Model presets (`backend.ai.models()`, requested once on first
96
96
  * use, without keys) plus user profiles that live only in this browser's localStorage (their key goes with each
97
97
  * request). Framework-free: `modelRef(slot)` is what AI requests send as `model`. Frameworks observe `presets`,
98
- * `userProfiles` and `app.settings` (the slot assignment is `settings.ai.slots`).
98
+ * `userProfiles` and `app.settings` (the Model role assignment is `settings.ai.roles`).
99
99
  */
100
100
  function modelProfiles(app) {
101
101
  let model = models.get(app);
@@ -1 +1 @@
1
- {"version":3,"file":"model-profiles.js","names":[],"sources":["../../../src/features/ai/model-profiles.ts"],"sourcesContent":["import { z } from 'zod'\nimport type { EditorContext } from '../../core/context'\nimport { createStore, type ReadonlyStore, type Store } from '../../core/store'\nimport { MODEL_SLOTS, type ModelSlot } from '../../settings'\nimport type { ModelProfile, ModelRef, UserModelProfile } from './protocol'\n\nconst STORAGE_KEY = 'tiptap-editor:model-profiles'\n\n/** The model profiles of one app: see `modelProfiles`. */\nexport interface ModelProfilesModel {\n /** Server presets (`ai.models()`, without keys); empty until loaded. */\n presets: ReadonlyStore<ModelProfile[]>\n /** This browser's own profiles (localStorage). Change them through `saveUserProfile`/`removeUserProfile`. */\n userProfiles: Store<UserModelProfile[]>\n /** Presets, then user profiles. Reads the stores: call it again after either changed. */\n profiles: () => ModelProfile[]\n /**\n * Profile a slot runs on: the one the settings assign to it, else the server's default preset for the slot, else the\n * first preset; none before the presets loaded (unless the settings point at a user profile).\n */\n slotProfile: (slot: ModelSlot) => ModelProfile | undefined\n /** What AI requests send as `model`; works before the presets loaded (the default slot preset of `createEditor({ ai })`). */\n modelRef: (slot: ModelSlot) => ModelRef\n saveUserProfile: (profile: UserModelProfile) => void\n /** Also resets every slot that ran on the profile to the server default. */\n removeUserProfile: (id: string) => void\n}\n\nconst storedProfileSchema = z.object({ id: z.string(), label: z.string(), endpoint: z.string(), model: z.string(), apiKey: z.string() })\n\nfunction storeUserProfiles(profiles: UserModelProfile[]) {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(profiles))\n }\n catch {\n // Storage unavailable (e.g. privacy mode): the profiles last for this session only.\n }\n}\n\nfunction loadUserProfiles(): UserModelProfile[] {\n try {\n const stored: unknown = JSON.parse(localStorage.getItem(STORAGE_KEY) ?? '[]')\n if (Array.isArray(stored)) {\n return stored.flatMap((item) => {\n const parsed = storedProfileSchema.safeParse(item)\n return parsed.success ? [parsed.data] : []\n })\n }\n }\n catch {\n // Unreadable or corrupt storage: no user profiles.\n }\n return []\n}\n\nfunction createModelProfiles(app: EditorContext): ModelProfilesModel {\n const presets = createStore<ModelProfile[]>([])\n const userProfiles = createStore<UserModelProfile[]>(loadUserProfiles())\n /** Default preset id per slot as the server reports it; until then the app's public AI configuration. */\n let serverSlots: Record<ModelSlot, string> | null = null\n const defaultSlots: Record<ModelSlot, string> = app.ai?.slots ?? { complete: '', rewrite: '', generate: '' }\n\n // A backend without `ai` has no server presets: requests keep using the default slot presets by id.\n app.backend.ai?.models()\n .then((response) => {\n serverSlots = response.slots\n presets.set(response.presets)\n })\n .catch((error) => {\n // Requests keep using the default slot presets by id.\n console.warn('tiptap-editor: Modell-Presets konnten nicht geladen werden', error)\n })\n\n const profiles = (): ModelProfile[] => [\n ...presets.get(),\n ...userProfiles.get().map(({ id, label, endpoint, model }) => ({ id, label, endpoint, model, source: 'user' as const })),\n ]\n\n const slotProfile = (slot: ModelSlot): ModelProfile | undefined => {\n const chosen = app.settings.get().ai.slots[slot]\n const defaultId = (serverSlots ?? defaultSlots)[slot]\n return profiles().find(p => p.id === chosen)\n ?? presets.get().find(p => p.id === defaultId)\n ?? presets.get()[0]\n }\n\n const modelRef = (slot: ModelSlot): ModelRef => {\n const profile = slotProfile(slot)\n if (!profile) return { preset: (serverSlots ?? defaultSlots)[slot] }\n const user = profile.source === 'user' ? userProfiles.get().find(p => p.id === profile.id) : undefined\n return user ? { endpoint: user.endpoint, model: user.model, apiKey: user.apiKey } : { preset: profile.id }\n }\n\n const saveUserProfile = (profile: UserModelProfile) => {\n const current = userProfiles.get()\n const index = current.findIndex(p => p.id === profile.id)\n const next = index < 0 ? [...current, profile] : current.map((p, i) => (i === index ? profile : p))\n userProfiles.set(next)\n storeUserProfiles(next)\n }\n\n const removeUserProfile = (id: string) => {\n const next = userProfiles.get().filter(p => p.id !== id)\n userProfiles.set(next)\n storeUserProfiles(next)\n const slots = app.settings.get().ai.slots\n if (MODEL_SLOTS.some(slot => slots[slot] === id)) {\n app.settings.update((s) => {\n for (const slot of MODEL_SLOTS) {\n if (s.ai.slots[slot] === id) delete s.ai.slots[slot]\n }\n })\n }\n }\n\n return { presets, userProfiles, profiles, slotProfile, modelRef, saveUserProfile, removeUserProfile }\n}\n\nconst models = new WeakMap<EditorContext, ModelProfilesModel>()\n\n/**\n * Model profiles the AI features run on, shared by all editors of the app (cached per `createEditorContext`, never\n * process-global): server presets (`backend.ai.models()`, requested once on first\n * use, without keys) plus user profiles that live only in this browser's localStorage (their key goes with each\n * request). Framework-free: `modelRef(slot)` is what AI requests send as `model`. Frameworks observe `presets`,\n * `userProfiles` and `app.settings` (the slot assignment is `settings.ai.slots`).\n */\nexport function modelProfiles(app: EditorContext): ModelProfilesModel {\n let model = models.get(app)\n if (!model) {\n model = createModelProfiles(app)\n models.set(app, model)\n }\n return model\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"model-profiles.js","names":[],"sources":["../../../src/features/ai/model-profiles.ts"],"sourcesContent":["import { z } from 'zod'\nimport type { EditorContext } from '../../core/context'\nimport { createStore, type ReadonlyStore, type Store } from '../../core/store'\nimport { MODEL_ROLES, type ModelRole } from '../../settings'\nimport type { ModelProfile, ModelRef, UserModelProfile } from './protocol'\n\nconst STORAGE_KEY = 'tiptap-editor:model-profiles'\n\n/** The model profiles of one app: see `modelProfiles`. */\nexport interface ModelProfilesModel {\n /** Server presets (`ai.models()`, without keys); empty until loaded. */\n presets: ReadonlyStore<ModelProfile[]>\n /** This browser's own profiles (localStorage). Change them through `saveUserProfile`/`removeUserProfile`. */\n userProfiles: Store<UserModelProfile[]>\n /** Presets, then user profiles. Reads the stores: call it again after either changed. */\n profiles: () => ModelProfile[]\n /**\n * Profile a Model role runs on: the one the settings assign to it, else the server's default Model preset for the Model role, else the\n * first Model preset; none before the Model presets loaded (unless the settings point at a user profile).\n */\n slotProfile: (slot: ModelRole) => ModelProfile | undefined\n /** What AI requests send as `model`; works before the Model presets loaded (the default Model preset of the role of `createEditor({ ai })`). */\n modelRef: (slot: ModelRole) => ModelRef\n saveUserProfile: (profile: UserModelProfile) => void\n /** Also resets every Model role that ran on the profile to the server default. */\n removeUserProfile: (id: string) => void\n}\n\nconst storedProfileSchema = z.object({ id: z.string(), label: z.string(), endpoint: z.string(), model: z.string(), apiKey: z.string() })\n\nfunction storeUserProfiles(profiles: UserModelProfile[]) {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(profiles))\n }\n catch {\n // Storage unavailable (e.g. privacy mode): the profiles last for this session only.\n }\n}\n\nfunction loadUserProfiles(): UserModelProfile[] {\n try {\n const stored: unknown = JSON.parse(localStorage.getItem(STORAGE_KEY) ?? '[]')\n if (Array.isArray(stored)) {\n return stored.flatMap((item) => {\n const parsed = storedProfileSchema.safeParse(item)\n return parsed.success ? [parsed.data] : []\n })\n }\n }\n catch {\n // Unreadable or corrupt storage: no user profiles.\n }\n return []\n}\n\nfunction createModelProfiles(app: EditorContext): ModelProfilesModel {\n const presets = createStore<ModelProfile[]>([])\n const userProfiles = createStore<UserModelProfile[]>(loadUserProfiles())\n /** Default Model preset id per Model role as the server reports it; until then the app's public AI configuration. */\n let serverRoles: Record<ModelRole, string> | null = null\n const defaultRoles: Record<ModelRole, string> = app.ai?.roles ?? { complete: '', rewrite: '', generate: '' }\n\n // A backend without `ai` has no Model presets: requests keep using the default Model presets of the Model roles by id.\n app.backend.ai?.models()\n .then((response) => {\n serverRoles = response.roles\n presets.set(response.presets)\n })\n .catch((error) => {\n // Requests keep using the default Model presets of the Model roles by id.\n console.warn('tiptap-editor: Modell-Presets konnten nicht geladen werden', error)\n })\n\n const profiles = (): ModelProfile[] => [\n ...presets.get(),\n ...userProfiles.get().map(({ id, label, endpoint, model }) => ({ id, label, endpoint, model, source: 'user' as const })),\n ]\n\n const slotProfile = (slot: ModelRole): ModelProfile | undefined => {\n const chosen = app.settings.get().ai.roles[slot]\n const defaultId = (serverRoles ?? defaultRoles)[slot]\n return profiles().find(p => p.id === chosen)\n ?? presets.get().find(p => p.id === defaultId)\n ?? presets.get()[0]\n }\n\n const modelRef = (slot: ModelRole): ModelRef => {\n const profile = slotProfile(slot)\n if (!profile) return { preset: (serverRoles ?? defaultRoles)[slot] }\n const user = profile.source === 'user' ? userProfiles.get().find(p => p.id === profile.id) : undefined\n return user ? { endpoint: user.endpoint, model: user.model, apiKey: user.apiKey } : { preset: profile.id }\n }\n\n const saveUserProfile = (profile: UserModelProfile) => {\n const current = userProfiles.get()\n const index = current.findIndex(p => p.id === profile.id)\n const next = index < 0 ? [...current, profile] : current.map((p, i) => (i === index ? profile : p))\n userProfiles.set(next)\n storeUserProfiles(next)\n }\n\n const removeUserProfile = (id: string) => {\n const next = userProfiles.get().filter(p => p.id !== id)\n userProfiles.set(next)\n storeUserProfiles(next)\n const roles = app.settings.get().ai.roles\n if (MODEL_ROLES.some(slot => roles[slot] === id)) {\n app.settings.update((s) => {\n for (const slot of MODEL_ROLES) {\n if (s.ai.roles[slot] === id) delete s.ai.roles[slot]\n }\n })\n }\n }\n\n return { presets, userProfiles, profiles, slotProfile, modelRef, saveUserProfile, removeUserProfile }\n}\n\nconst models = new WeakMap<EditorContext, ModelProfilesModel>()\n\n/**\n * Model profiles the AI features run on, shared by all editors of the app (cached per `createEditorContext`, never\n * process-global): Model presets (`backend.ai.models()`, requested once on first\n * use, without keys) plus user profiles that live only in this browser's localStorage (their key goes with each\n * request). Framework-free: `modelRef(slot)` is what AI requests send as `model`. Frameworks observe `presets`,\n * `userProfiles` and `app.settings` (the Model role assignment is `settings.ai.roles`).\n */\nexport function modelProfiles(app: EditorContext): ModelProfilesModel {\n let model = models.get(app)\n if (!model) {\n model = createModelProfiles(app)\n models.set(app, model)\n }\n return model\n}\n"],"mappings":"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"}
@@ -16,7 +16,7 @@ export type AgentOpType = typeof AGENT_OP_TYPES[number];
16
16
  * One proposed edit as the model writes it: `update` replaces block `id` by `markdown`, `delete` removes block `id`,
17
17
  * `add` inserts `markdown` (one or more blocks) after block `afterId` (`null`: at the start of the document; the key
18
18
  * is required), `convert` turns block `id` into the block type `to` (a `CONVERT_TARGET_IDS` entry or
19
- * `composite:<kind>`), keeping its content.
19
+ * `typedBlock:<kind>`), keeping its content.
20
20
  */
21
21
  export type ModelAgentOp = {
22
22
  type: 'update';
@@ -86,7 +86,7 @@ export declare const AGENT_OP_OUTCOME_TEXT: Record<Locale, Record<AgentOpOutcome
86
86
  export interface AgentTextOptions {
87
87
  locale?: Locale;
88
88
  }
89
- /** `update Block X`, `add nach Block X`, `add am Dokumentanfang`, `convert Block X → composite:task` (`to` when known); English with `locale: 'en'`. */
89
+ /** `update Block X`, `add nach Block X`, `add am Dokumentanfang`, `convert Block X → typedBlock:task` (`to` when known); English with `locale: 'en'`. */
90
90
  export declare function agentOpSummary(op: {
91
91
  type: AgentOpType;
92
92
  target: string | null;
@@ -159,7 +159,7 @@ const AGENT_OP_OUTCOME_TEXT = {
159
159
  de: AGENT_TEXTS.de.outcome,
160
160
  en: AGENT_TEXTS.en.outcome
161
161
  };
162
- /** `update Block X`, `add nach Block X`, `add am Dokumentanfang`, `convert Block X → composite:task` (`to` when known); English with `locale: 'en'`. */
162
+ /** `update Block X`, `add nach Block X`, `add am Dokumentanfang`, `convert Block X → typedBlock:task` (`to` when known); English with `locale: 'en'`. */
163
163
  function agentOpSummary(op, { locale = "de" } = {}) {
164
164
  const text = AGENT_TEXTS[locale].summary;
165
165
  if (op.type === "convert" && op.to) return text.convert(op.target, op.to);
@@ -1 +1 @@
1
- {"version":3,"file":"agent-ops.js","names":[],"sources":["../../../../src/features/ai/protocol/agent-ops.ts"],"sourcesContent":["// i18n-ignore-file: model-facing tool results, operation checks and decision texts (German by default, English on request; the model's language is not the editor's)\n/**\n * Agent operations of the document chat: the model proposes block edits through the `edit_document` tool, the server\n * checks every block ID against the document and the scope, and the client shows the valid ones as in-document review.\n */\nimport type { Locale } from '../../../i18n'\n\nimport { BLOCK_LINE_IDS_HINT, type BlockLines, stripBlockLineEcho } from './block-lines'\n\n/** Name of the tool the chat model calls to propose edits. */\nexport const AGENT_TOOL = 'edit_document'\n\n/** Per-turn limits: operations, Markdown per operation, IDs in a selection scope; retries after invalid IDs. */\nexport const AGENT_LIMITS = { ops: 50, markdown: 8000, scope: 5000, retries: 2 } as const\n\nexport const AGENT_OP_TYPES = ['add', 'update', 'delete', 'convert'] as const\nexport type AgentOpType = typeof AGENT_OP_TYPES[number]\n\n/**\n * One proposed edit as the model writes it: `update` replaces block `id` by `markdown`, `delete` removes block `id`,\n * `add` inserts `markdown` (one or more blocks) after block `afterId` (`null`: at the start of the document; the key\n * is required), `convert` turns block `id` into the block type `to` (a `CONVERT_TARGET_IDS` entry or\n * `composite:<kind>`), keeping its content.\n */\nexport type ModelAgentOp =\n | { type: 'update', id: string, markdown: string }\n | { type: 'delete', id: string }\n | { type: 'add', afterId: string | null, markdown: string }\n | { type: 'convert', id: string, to: string }\n\n/** A checked operation with the conversation-wide ID (`op1`, `op2`, …) that decisions refer to. */\nexport type AgentOp = ModelAgentOp & { op: string }\n\n/**\n * What became of an operation: decided in the review (`accepted`, `rejected`, `partial` for mixed hunks, `invalid`\n * when its text changed underneath), still `pending`, or never reviewed: the client found its block deleted since the\n * document went to the model (`stale`) or refused it as out of scope (`blocked`), or the review found nothing to show\n * (`unchanged`, `missing` block, `overlap` with open AI changes, `empty` result).\n */\nexport const AGENT_OP_OUTCOMES = ['accepted', 'rejected', 'partial', 'invalid', 'pending', 'unchanged', 'missing', 'stale', 'overlap', 'empty', 'blocked'] as const\nexport type AgentOpOutcome = typeof AGENT_OP_OUTCOMES[number]\n\n/** Decision state of an earlier operation, sent with the next user message. */\nexport interface AgentOpFeedback { op: string, type: AgentOpType, target: string | null, outcome: AgentOpOutcome }\n\n/**\n * Why an operation was dropped: unknown block ID, ID outside the scope, a missing/invalid field, a block edited twice,\n * too many ops, a `convert` target that is not offered, a block inside another block that an operation of the same\n * answer replaces or deletes (`inside`).\n */\nexport type AgentOpProblemReason = 'unknown' | 'scope' | 'field' | 'duplicate' | 'limit' | 'target' | 'inside'\n\n/** A dropped operation: its 1-based position in the tool call, type and target as far as readable, and the offending ID. */\nexport interface AgentOpProblem { index: number, type: string | null, id: string | null, reason: AgentOpProblemReason, detail: string }\n\n/**\n * Where operations may point: `lines` the block IDs of the document text and which blocks lie inside which (see\n * `readBlockLines`); `allowed` the selection scope (null: the whole document); `targets` the block types `convert`\n * may turn a block into; `locale` the language of the problem details (default `de`).\n */\nexport interface AgentOpContext { lines: BlockLines, allowed: ReadonlySet<string> | null, targets: ReadonlySet<string>, locale?: Locale }\n\n/** The block an operation targets: `update`/`delete` its `id`, `add` its `afterId` (null: document start). */\nexport function agentOpTarget(op: ModelAgentOp): string | null {\n return op.type === 'add' ? op.afterId : op.id\n}\n\n/**\n * Every model-facing text of the agent protocol, per locale (the editor's own prompts in chat.ts stay German). Selected\n * by the `locale` option of the functions below; `de` is the default and what existing hosts receive.\n */\ninterface AgentTexts {\n /** How an outcome reads for the model. */\n outcome: Record<AgentOpOutcome, string>\n summary: {\n convert: (target: string | null, to: string) => string\n block: (type: string, target: string | null) => string\n addStart: string\n addAfter: (target: string) => string\n }\n problem: {\n limit: (max: number) => string\n type: (allowed: string) => string\n addAtStart: string\n idMissing: (field: string) => string\n unknownId: (id: string) => string\n outsideScope: (id: string) => string\n duplicate: (id: string) => string\n toMissing: string\n badTarget: (to: string, allowed: string) => string\n markdownMissing: string\n markdownMissingUpdate: string\n markdownTooLong: (max: number) => string\n unreadable: string\n afterIdMissing: string\n afterIdMissingScoped: string\n inside: (target: string, owner: string, ownerIndex: number, deletes: boolean) => string\n }\n retry: {\n failed: string\n failedPartial: string\n invalidIds: (ids: string) => string\n operation: (index: number, type: string | null, detail: string) => string\n scoped: string\n unscoped: string\n inside: string\n again: (tool: string) => string\n againPartial: (tool: string) => string\n }\n shown: {\n shown: (ops: string) => string\n none: string\n dropped: (count: number) => string\n decisions: string\n }\n feedback: (decisions: string) => string\n}\n\nconst AGENT_TEXTS: Record<Locale, AgentTexts> = {\n de: {\n outcome: {\n accepted: 'übernommen',\n rejected: 'abgelehnt',\n partial: 'teilweise übernommen',\n invalid: 'verfallen, weil der Text inzwischen anders geändert wurde',\n pending: 'noch nicht entschieden',\n unchanged: 'nicht angezeigt, weil er dem vorhandenen Text entspricht',\n missing: 'nicht angezeigt, weil der Block nicht mehr existiert',\n overlap: 'nicht angezeigt, weil an der Stelle noch andere KI-Änderungen offen sind',\n empty: 'nicht angezeigt, weil der Inhalt leer ist',\n stale: 'nicht angezeigt: Block wurde inzwischen gelöscht',\n blocked: 'blockiert, weil er außerhalb des erlaubten Bereichs liegt',\n },\n summary: {\n convert: (target, to) => `convert Block ${target} → ${to}`,\n block: (type, target) => `${type} Block ${target}`,\n addStart: 'add am Dokumentanfang',\n addAfter: target => `add nach Block ${target}`,\n },\n problem: {\n limit: max => `mehr als ${max} Operationen`,\n type: allowed => `unbekannter oder fehlender Typ (erlaubt: ${allowed})`,\n addAtStart: 'Einfügen am Dokumentanfang liegt außerhalb der Auswahl; afterId muss ein ausgewählter Block sein',\n idMissing: field => `${field} fehlt`,\n unknownId: id => `die ID „${id}“ gibt es im Dokument nicht`,\n outsideScope: id => `die ID „${id}“ liegt außerhalb der Auswahl`,\n duplicate: id => `der Block „${id}“ wird mehrfach geändert oder gelöscht`,\n toMissing: 'to fehlt',\n badTarget: (to, allowed) => `„${to}“ ist kein erlaubter Blocktyp für to (erlaubt: ${allowed})`,\n markdownMissing: 'markdown fehlt',\n markdownMissingUpdate: 'markdown fehlt (zum Entfernen „delete“ verwenden)',\n markdownTooLong: max => `markdown ist länger als ${max} Zeichen`,\n unreadable: 'die Eingabe war kein Objekt mit der Liste „ops“',\n afterIdMissing: 'afterId fehlt; für den Dokumentanfang ausdrücklich null schreiben',\n afterIdMissingScoped: 'afterId fehlt; es muss ein ausgewählter Block sein',\n inside: (target, owner, ownerIndex, deletes) => `Block ${target} liegt in ${owner}, das Operation ${ownerIndex} ${deletes ? 'löscht' : 'ersetzt'}`,\n },\n retry: {\n failed: 'Fehler: Die Operationen wurden nicht angewendet, weil einige ungültig sind.',\n failedPartial: 'Fehler: Einige Operationen sind ungültig und wurden verworfen; die übrigen werden zur Prüfung angezeigt.',\n invalidIds: ids => `Ungültige IDs: ${ids}`,\n operation: (index, type, detail) => `- Operation ${index}${type ? ` (${type})` : ''}: ${detail}`,\n inside: 'Eine Operation auf einen Block innerhalb eines ersetzten oder gelöschten Blocks entfällt: die Operation auf den äußeren Block gilt. Soll der innere Block mitgeändert werden, schreibe die Änderung in das Markdown der äußeren Operation.',\n scoped: 'Verwende nur IDs aus dem Bearbeitungsbereich (siehe Nachricht); erfinde keine IDs.',\n unscoped: BLOCK_LINE_IDS_HINT,\n again: tool => `Rufe ${tool} erneut mit der vollständigen, korrigierten Liste aller Operationen auf. Lass Operationen weg, die sich nicht korrigieren lassen.`,\n againPartial: tool => `Rufe ${tool} erneut nur mit den korrigierten Fassungen der oben genannten Operationen auf; wiederhole die angezeigten nicht. Lass Operationen weg, die sich nicht korrigieren lassen.`,\n },\n shown: {\n shown: ops => `Zur Prüfung im Dokument angezeigt: ${ops}.`,\n none: 'Keine der Operationen wurde angezeigt.',\n dropped: count => `${count} Operation(en) mit ungültigen IDs wurden verworfen; die Nutzerin bzw. der Nutzer wurde darauf hingewiesen.`,\n decisions: 'Die Nutzerin bzw. der Nutzer übernimmt oder verwirft jede Änderung im Dokument; die Entscheidungen folgen mit einer späteren Nachricht.',\n },\n feedback: decisions => `Entscheidungen zu deinen letzten Vorschlägen: ${decisions}.`,\n },\n en: {\n outcome: {\n accepted: 'accepted',\n rejected: 'rejected',\n partial: 'partially accepted',\n invalid: 'lapsed because the text was changed in the meantime',\n pending: 'not decided yet',\n unchanged: 'not shown because it matches the existing text',\n missing: 'not shown because the block no longer exists',\n overlap: 'not shown because other AI changes are still open at that place',\n empty: 'not shown because the content is empty',\n stale: 'not shown: the block was deleted in the meantime',\n blocked: 'blocked because it lies outside the allowed scope',\n },\n summary: {\n convert: (target, to) => `convert block ${target} → ${to}`,\n block: (type, target) => `${type} block ${target}`,\n addStart: 'add at the start of the document',\n addAfter: target => `add after block ${target}`,\n },\n problem: {\n limit: max => `more than ${max} operations`,\n type: allowed => `unknown or missing type (allowed: ${allowed})`,\n addAtStart: 'inserting at the start of the document is outside the selection; afterId must be a selected block',\n idMissing: field => `${field} is missing`,\n unknownId: id => `the ID \"${id}\" does not exist in the document`,\n outsideScope: id => `the ID \"${id}\" is outside the selection`,\n duplicate: id => `the block \"${id}\" is changed or deleted more than once`,\n toMissing: 'to is missing',\n badTarget: (to, allowed) => `\"${to}\" is not an allowed block type for to (allowed: ${allowed})`,\n markdownMissing: 'markdown is missing',\n markdownMissingUpdate: 'markdown is missing (use \"delete\" to remove a block)',\n markdownTooLong: max => `markdown is longer than ${max} characters`,\n unreadable: 'the input was not an object with the list \"ops\"',\n afterIdMissing: 'afterId is missing; write null explicitly for the start of the document',\n afterIdMissingScoped: 'afterId is missing; it must be a selected block',\n inside: (target, owner, ownerIndex, deletes) => `block ${target} lies inside ${owner}, which operation ${ownerIndex} ${deletes ? 'deletes' : 'replaces'}`,\n },\n retry: {\n failed: 'Error: The operations were not applied because some of them are invalid.',\n failedPartial: 'Error: Some operations are invalid and were dropped; the others are shown for review.',\n invalidIds: ids => `Invalid IDs: ${ids}`,\n operation: (index, type, detail) => `- Operation ${index}${type ? ` (${type})` : ''}: ${detail}`,\n inside: 'An operation on a block inside a replaced or deleted block is dropped: the operation on the outer block applies. To change the inner block as well, write the change into the Markdown of the outer operation.',\n scoped: 'Use only IDs from the editing scope (see message); do not invent IDs.',\n unscoped: 'Use only IDs that appear in square brackets in the document; do not invent IDs.',\n again: tool => `Call ${tool} again with the complete, corrected list of all operations. Leave out operations that cannot be corrected.`,\n againPartial: tool => `Call ${tool} again with corrected versions of only the operations listed above; do not repeat the shown ones. Leave out operations that cannot be corrected.`,\n },\n shown: {\n shown: ops => `Shown in the document for review: ${ops}.`,\n none: 'None of the operations were shown.',\n dropped: count => `${count} operation(s) with invalid IDs were dropped; the user has been notified.`,\n decisions: 'The user accepts or rejects each change in the document; the decisions follow with a later message.',\n },\n feedback: decisions => `Decisions on your latest proposals: ${decisions}.`,\n },\n}\n\n/** How an outcome reads for the model, per locale; the chat shows the catalog's `ai.opTitle.*` texts. */\nexport const AGENT_OP_OUTCOME_TEXT: Record<Locale, Record<AgentOpOutcome, string>> = {\n de: AGENT_TEXTS.de.outcome,\n en: AGENT_TEXTS.en.outcome,\n}\n\n/** Text options of the model-facing functions: `locale` selects the language (default `de`). */\nexport interface AgentTextOptions { locale?: Locale }\n\n/** `update Block X`, `add nach Block X`, `add am Dokumentanfang`, `convert Block X → composite:task` (`to` when known); English with `locale: 'en'`. */\nexport function agentOpSummary(op: { type: AgentOpType, target: string | null, to?: string }, { locale = 'de' }: AgentTextOptions = {}): string {\n const text = AGENT_TEXTS[locale].summary\n if (op.type === 'convert' && op.to) return text.convert(op.target, op.to)\n if (op.type !== 'add') return text.block(op.type, op.target)\n return op.target === null ? text.addStart : text.addAfter(op.target)\n}\n\n/**\n * Checks the raw `ops` of `edit_document` calls: every ID must exist and lie in the scope (`add` needs its `afterId`\n * key, `null` for the document start, and in a selection scope an `afterId` from the selection), fields must be\n * present, a `convert` target must be one of `targets`, a block is updated, converted or deleted at most once, and no\n * operation may point into a block (`lines.below`) that another operation replaces (`update`) or deletes: the\n * operation on the outer block wins. Several `add`s after the same block are fine; the client inserts them in the\n * order they were written. Returns the valid operations in order and the problems of the others; the problems'\n * `detail` is written in `context.locale` (default `de`).\n */\nexport function checkAgentOps(raw: readonly unknown[], context: AgentOpContext): { valid: ModelAgentOp[], problems: AgentOpProblem[] } {\n const accepted: { op: ModelAgentOp, index: number }[] = []\n const problems: AgentOpProblem[] = []\n const edited = new Set<string>()\n const text = AGENT_TEXTS[context.locale ?? 'de'].problem\n const known = (id: string) => context.lines.ids.has(id)\n\n raw.forEach((entry, i) => {\n const index = i + 1\n const value = (entry && typeof entry === 'object' ? entry : {}) as Record<string, unknown>\n const type = typeof value.type === 'string' ? value.type : null\n const problem = (reason: AgentOpProblemReason, id: string | null, detail: string) => problems.push({ index, type, id, reason, detail })\n const accept = (op: ModelAgentOp) => accepted.push({ op, index })\n\n if (index > AGENT_LIMITS.ops) return problem('limit', null, text.limit(AGENT_LIMITS.ops))\n if (!type || !(AGENT_OP_TYPES as readonly string[]).includes(type)) return problem('field', null, text.type(AGENT_OP_TYPES.join(', ')))\n\n const idField = type === 'add' ? 'afterId' : 'id'\n const rawId = value[idField]\n // `afterId: null` is the document start; a forgotten key must not become one.\n if (type === 'add' && rawId === undefined) {\n return problem('field', null, context.allowed ? text.afterIdMissingScoped : text.afterIdMissing)\n }\n if (type === 'add' && rawId === null) {\n if (context.allowed) return problem('scope', null, text.addAtStart)\n }\n else if (typeof rawId !== 'string' || !rawId.trim()) {\n return problem('field', null, text.idMissing(idField))\n }\n const id = typeof rawId === 'string' ? rawId.trim() : null\n if (id !== null) {\n if (!known(id)) return problem('unknown', id, text.unknownId(id))\n if (context.allowed && !context.allowed.has(id)) return problem('scope', id, text.outsideScope(id))\n }\n\n if (type === 'delete') {\n if (edited.has(id!)) return problem('duplicate', id, text.duplicate(id!))\n edited.add(id!)\n return accept({ type, id: id! })\n }\n\n if (type === 'convert') {\n const to = typeof value.to === 'string' ? value.to.trim() : ''\n if (!to) return problem('field', id, text.toMissing)\n if (!context.targets.has(to)) return problem('target', id, text.badTarget(to, [...context.targets].join(', ')))\n if (edited.has(id!)) return problem('duplicate', id, text.duplicate(id!))\n edited.add(id!)\n return accept({ type, id: id!, to })\n }\n\n const markdown = typeof value.markdown === 'string' ? stripBlockLineEcho(value.markdown, known).trim() : ''\n if (!markdown) return problem('field', id, type === 'update' ? text.markdownMissingUpdate : text.markdownMissing)\n if (markdown.length > AGENT_LIMITS.markdown) return problem('field', id, text.markdownTooLong(AGENT_LIMITS.markdown))\n if (type === 'add') return accept({ type, afterId: id, markdown })\n if (edited.has(id!)) return problem('duplicate', id, text.duplicate(id!))\n edited.add(id!)\n accept({ type: 'update', id: id!, markdown })\n })\n\n // An operation on a block inside another operation's block is dropped, naming the outermost operation that covers it.\n const owners = accepted.filter(({ op }) => op.type === 'update' || op.type === 'delete')\n const covering = ({ op }: typeof accepted[number]) => {\n const target = agentOpTarget(op)\n return target === null ? [] : owners.filter(owner => context.lines.below(agentOpTarget(owner.op)!).has(target))\n }\n const valid: ModelAgentOp[] = []\n for (const entry of accepted) {\n const cover = covering(entry)\n const owner = cover.find(candidate => !covering(candidate).length) ?? cover[0]\n if (!owner) {\n valid.push(entry.op)\n continue\n }\n const target = agentOpTarget(entry.op)!\n problems.push({\n index: entry.index,\n type: entry.op.type,\n id: target,\n reason: 'inside',\n detail: text.inside(target, agentOpTarget(owner.op)!, owner.index, owner.op.type === 'delete'),\n })\n }\n problems.sort((a, b) => a.index - b.index)\n return { valid, problems }\n}\n\n/** The problem for a tool call whose input was no object with the list `ops` (index 0), worded in `locale` (default `de`). */\nexport function agentUnreadableProblem({ locale = 'de' }: AgentTextOptions = {}): AgentOpProblem {\n return { index: 0, type: null, id: null, reason: 'field', detail: AGENT_TEXTS[locale].problem.unreadable }\n}\n\n/**\n * Tool result asking the model to call `tool` (default `edit_document`, the host's own tool name when it exposes the\n * operations under another one) again without the invalid operations' mistakes; worded in `locale` (default `de`).\n * By default nothing was applied and the model resends the whole list; with `partial` the host already shows the\n * valid operations, so the model resends only corrected versions of the listed ones.\n */\nexport function agentRetryMessage(\n problems: readonly AgentOpProblem[],\n scoped: boolean,\n { locale = 'de', tool = AGENT_TOOL, partial = false }: AgentTextOptions & { tool?: string, partial?: boolean } = {},\n): string {\n const text = AGENT_TEXTS[locale].retry\n const ids = [...new Set(problems.filter(p => p.reason !== 'inside').map(p => p.id).filter((id): id is string => !!id))]\n return [\n partial ? text.failedPartial : text.failed,\n ...(ids.length ? [text.invalidIds(ids.join(', '))] : []),\n ...problems.map(p => text.operation(p.index, p.type, p.detail)),\n ...(problems.some(p => p.reason === 'inside') ? [text.inside] : []),\n scoped ? text.scoped : text.unscoped,\n partial ? text.againPartial(tool) : text.again(tool),\n ].join('\\n')\n}\n\n/** Tool result of a past `edit_document` call: which operations were shown for review, and how many were dropped; worded in `locale` (default `de`). */\nexport function agentShownMessage(ops: readonly AgentOp[], dropped: number, { locale = 'de' }: AgentTextOptions = {}): string {\n const text = AGENT_TEXTS[locale].shown\n const lines = ops.length\n ? [text.shown(ops.map(op => `${op.op} (${agentOpSummary({ ...op, target: agentOpTarget(op) }, { locale })})`).join(', '))]\n : [text.none]\n if (dropped) lines.push(text.dropped(dropped))\n lines.push(text.decisions)\n return lines.join(' ')\n}\n\n/** „Entscheidungen zu deinen letzten Vorschlägen: op1 (update Block X) abgelehnt; …“ (English with `locale: 'en'`), or '' without feedback. */\nexport function agentFeedbackText(feedback: readonly AgentOpFeedback[], { locale = 'de' }: AgentTextOptions = {}): string {\n if (!feedback.length) return ''\n const outcome = AGENT_TEXTS[locale].outcome\n return AGENT_TEXTS[locale].feedback(feedback.map(f => `${f.op} (${agentOpSummary(f, { locale })}) ${outcome[f.outcome]}`).join('; '))\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"agent-ops.js","names":[],"sources":["../../../../src/features/ai/protocol/agent-ops.ts"],"sourcesContent":["// i18n-ignore-file: model-facing tool results, operation checks and decision texts (German by default, English on request; the model's language is not the editor's)\n/**\n * Agent operations of the document chat: the model proposes block edits through the `edit_document` tool, the server\n * checks every block ID against the document and the scope, and the client shows the valid ones as in-document review.\n */\nimport type { Locale } from '../../../i18n'\n\nimport { BLOCK_LINE_IDS_HINT, type BlockLines, stripBlockLineEcho } from './block-lines'\n\n/** Name of the tool the chat model calls to propose edits. */\nexport const AGENT_TOOL = 'edit_document'\n\n/** Per-turn limits: operations, Markdown per operation, IDs in a selection scope; retries after invalid IDs. */\nexport const AGENT_LIMITS = { ops: 50, markdown: 8000, scope: 5000, retries: 2 } as const\n\nexport const AGENT_OP_TYPES = ['add', 'update', 'delete', 'convert'] as const\nexport type AgentOpType = typeof AGENT_OP_TYPES[number]\n\n/**\n * One proposed edit as the model writes it: `update` replaces block `id` by `markdown`, `delete` removes block `id`,\n * `add` inserts `markdown` (one or more blocks) after block `afterId` (`null`: at the start of the document; the key\n * is required), `convert` turns block `id` into the block type `to` (a `CONVERT_TARGET_IDS` entry or\n * `typedBlock:<kind>`), keeping its content.\n */\nexport type ModelAgentOp =\n | { type: 'update', id: string, markdown: string }\n | { type: 'delete', id: string }\n | { type: 'add', afterId: string | null, markdown: string }\n | { type: 'convert', id: string, to: string }\n\n/** A checked operation with the conversation-wide ID (`op1`, `op2`, …) that decisions refer to. */\nexport type AgentOp = ModelAgentOp & { op: string }\n\n/**\n * What became of an operation: decided in the review (`accepted`, `rejected`, `partial` for mixed hunks, `invalid`\n * when its text changed underneath), still `pending`, or never reviewed: the client found its block deleted since the\n * document went to the model (`stale`) or refused it as out of scope (`blocked`), or the review found nothing to show\n * (`unchanged`, `missing` block, `overlap` with open AI changes, `empty` result).\n */\nexport const AGENT_OP_OUTCOMES = ['accepted', 'rejected', 'partial', 'invalid', 'pending', 'unchanged', 'missing', 'stale', 'overlap', 'empty', 'blocked'] as const\nexport type AgentOpOutcome = typeof AGENT_OP_OUTCOMES[number]\n\n/** Decision state of an earlier operation, sent with the next user message. */\nexport interface AgentOpFeedback { op: string, type: AgentOpType, target: string | null, outcome: AgentOpOutcome }\n\n/**\n * Why an operation was dropped: unknown block ID, ID outside the scope, a missing/invalid field, a block edited twice,\n * too many ops, a `convert` target that is not offered, a block inside another block that an operation of the same\n * answer replaces or deletes (`inside`).\n */\nexport type AgentOpProblemReason = 'unknown' | 'scope' | 'field' | 'duplicate' | 'limit' | 'target' | 'inside'\n\n/** A dropped operation: its 1-based position in the tool call, type and target as far as readable, and the offending ID. */\nexport interface AgentOpProblem { index: number, type: string | null, id: string | null, reason: AgentOpProblemReason, detail: string }\n\n/**\n * Where operations may point: `lines` the block IDs of the document text and which blocks lie inside which (see\n * `readBlockLines`); `allowed` the selection scope (null: the whole document); `targets` the block types `convert`\n * may turn a block into; `locale` the language of the problem details (default `de`).\n */\nexport interface AgentOpContext { lines: BlockLines, allowed: ReadonlySet<string> | null, targets: ReadonlySet<string>, locale?: Locale }\n\n/** The block an operation targets: `update`/`delete` its `id`, `add` its `afterId` (null: document start). */\nexport function agentOpTarget(op: ModelAgentOp): string | null {\n return op.type === 'add' ? op.afterId : op.id\n}\n\n/**\n * Every model-facing text of the agent protocol, per locale (the editor's own prompts in chat.ts stay German). Selected\n * by the `locale` option of the functions below; `de` is the default and what existing hosts receive.\n */\ninterface AgentTexts {\n /** How an outcome reads for the model. */\n outcome: Record<AgentOpOutcome, string>\n summary: {\n convert: (target: string | null, to: string) => string\n block: (type: string, target: string | null) => string\n addStart: string\n addAfter: (target: string) => string\n }\n problem: {\n limit: (max: number) => string\n type: (allowed: string) => string\n addAtStart: string\n idMissing: (field: string) => string\n unknownId: (id: string) => string\n outsideScope: (id: string) => string\n duplicate: (id: string) => string\n toMissing: string\n badTarget: (to: string, allowed: string) => string\n markdownMissing: string\n markdownMissingUpdate: string\n markdownTooLong: (max: number) => string\n unreadable: string\n afterIdMissing: string\n afterIdMissingScoped: string\n inside: (target: string, owner: string, ownerIndex: number, deletes: boolean) => string\n }\n retry: {\n failed: string\n failedPartial: string\n invalidIds: (ids: string) => string\n operation: (index: number, type: string | null, detail: string) => string\n scoped: string\n unscoped: string\n inside: string\n again: (tool: string) => string\n againPartial: (tool: string) => string\n }\n shown: {\n shown: (ops: string) => string\n none: string\n dropped: (count: number) => string\n decisions: string\n }\n feedback: (decisions: string) => string\n}\n\nconst AGENT_TEXTS: Record<Locale, AgentTexts> = {\n de: {\n outcome: {\n accepted: 'übernommen',\n rejected: 'abgelehnt',\n partial: 'teilweise übernommen',\n invalid: 'verfallen, weil der Text inzwischen anders geändert wurde',\n pending: 'noch nicht entschieden',\n unchanged: 'nicht angezeigt, weil er dem vorhandenen Text entspricht',\n missing: 'nicht angezeigt, weil der Block nicht mehr existiert',\n overlap: 'nicht angezeigt, weil an der Stelle noch andere KI-Änderungen offen sind',\n empty: 'nicht angezeigt, weil der Inhalt leer ist',\n stale: 'nicht angezeigt: Block wurde inzwischen gelöscht',\n blocked: 'blockiert, weil er außerhalb des erlaubten Bereichs liegt',\n },\n summary: {\n convert: (target, to) => `convert Block ${target} → ${to}`,\n block: (type, target) => `${type} Block ${target}`,\n addStart: 'add am Dokumentanfang',\n addAfter: target => `add nach Block ${target}`,\n },\n problem: {\n limit: max => `mehr als ${max} Operationen`,\n type: allowed => `unbekannter oder fehlender Typ (erlaubt: ${allowed})`,\n addAtStart: 'Einfügen am Dokumentanfang liegt außerhalb der Auswahl; afterId muss ein ausgewählter Block sein',\n idMissing: field => `${field} fehlt`,\n unknownId: id => `die ID „${id}“ gibt es im Dokument nicht`,\n outsideScope: id => `die ID „${id}“ liegt außerhalb der Auswahl`,\n duplicate: id => `der Block „${id}“ wird mehrfach geändert oder gelöscht`,\n toMissing: 'to fehlt',\n badTarget: (to, allowed) => `„${to}“ ist kein erlaubter Blocktyp für to (erlaubt: ${allowed})`,\n markdownMissing: 'markdown fehlt',\n markdownMissingUpdate: 'markdown fehlt (zum Entfernen „delete“ verwenden)',\n markdownTooLong: max => `markdown ist länger als ${max} Zeichen`,\n unreadable: 'die Eingabe war kein Objekt mit der Liste „ops“',\n afterIdMissing: 'afterId fehlt; für den Dokumentanfang ausdrücklich null schreiben',\n afterIdMissingScoped: 'afterId fehlt; es muss ein ausgewählter Block sein',\n inside: (target, owner, ownerIndex, deletes) => `Block ${target} liegt in ${owner}, das Operation ${ownerIndex} ${deletes ? 'löscht' : 'ersetzt'}`,\n },\n retry: {\n failed: 'Fehler: Die Operationen wurden nicht angewendet, weil einige ungültig sind.',\n failedPartial: 'Fehler: Einige Operationen sind ungültig und wurden verworfen; die übrigen werden zur Prüfung angezeigt.',\n invalidIds: ids => `Ungültige IDs: ${ids}`,\n operation: (index, type, detail) => `- Operation ${index}${type ? ` (${type})` : ''}: ${detail}`,\n inside: 'Eine Operation auf einen Block innerhalb eines ersetzten oder gelöschten Blocks entfällt: die Operation auf den äußeren Block gilt. Soll der innere Block mitgeändert werden, schreibe die Änderung in das Markdown der äußeren Operation.',\n scoped: 'Verwende nur IDs aus dem Bearbeitungsbereich (siehe Nachricht); erfinde keine IDs.',\n unscoped: BLOCK_LINE_IDS_HINT,\n again: tool => `Rufe ${tool} erneut mit der vollständigen, korrigierten Liste aller Operationen auf. Lass Operationen weg, die sich nicht korrigieren lassen.`,\n againPartial: tool => `Rufe ${tool} erneut nur mit den korrigierten Fassungen der oben genannten Operationen auf; wiederhole die angezeigten nicht. Lass Operationen weg, die sich nicht korrigieren lassen.`,\n },\n shown: {\n shown: ops => `Zur Prüfung im Dokument angezeigt: ${ops}.`,\n none: 'Keine der Operationen wurde angezeigt.',\n dropped: count => `${count} Operation(en) mit ungültigen IDs wurden verworfen; die Nutzerin bzw. der Nutzer wurde darauf hingewiesen.`,\n decisions: 'Die Nutzerin bzw. der Nutzer übernimmt oder verwirft jede Änderung im Dokument; die Entscheidungen folgen mit einer späteren Nachricht.',\n },\n feedback: decisions => `Entscheidungen zu deinen letzten Vorschlägen: ${decisions}.`,\n },\n en: {\n outcome: {\n accepted: 'accepted',\n rejected: 'rejected',\n partial: 'partially accepted',\n invalid: 'lapsed because the text was changed in the meantime',\n pending: 'not decided yet',\n unchanged: 'not shown because it matches the existing text',\n missing: 'not shown because the block no longer exists',\n overlap: 'not shown because other AI changes are still open at that place',\n empty: 'not shown because the content is empty',\n stale: 'not shown: the block was deleted in the meantime',\n blocked: 'blocked because it lies outside the allowed scope',\n },\n summary: {\n convert: (target, to) => `convert block ${target} → ${to}`,\n block: (type, target) => `${type} block ${target}`,\n addStart: 'add at the start of the document',\n addAfter: target => `add after block ${target}`,\n },\n problem: {\n limit: max => `more than ${max} operations`,\n type: allowed => `unknown or missing type (allowed: ${allowed})`,\n addAtStart: 'inserting at the start of the document is outside the selection; afterId must be a selected block',\n idMissing: field => `${field} is missing`,\n unknownId: id => `the ID \"${id}\" does not exist in the document`,\n outsideScope: id => `the ID \"${id}\" is outside the selection`,\n duplicate: id => `the block \"${id}\" is changed or deleted more than once`,\n toMissing: 'to is missing',\n badTarget: (to, allowed) => `\"${to}\" is not an allowed block type for to (allowed: ${allowed})`,\n markdownMissing: 'markdown is missing',\n markdownMissingUpdate: 'markdown is missing (use \"delete\" to remove a block)',\n markdownTooLong: max => `markdown is longer than ${max} characters`,\n unreadable: 'the input was not an object with the list \"ops\"',\n afterIdMissing: 'afterId is missing; write null explicitly for the start of the document',\n afterIdMissingScoped: 'afterId is missing; it must be a selected block',\n inside: (target, owner, ownerIndex, deletes) => `block ${target} lies inside ${owner}, which operation ${ownerIndex} ${deletes ? 'deletes' : 'replaces'}`,\n },\n retry: {\n failed: 'Error: The operations were not applied because some of them are invalid.',\n failedPartial: 'Error: Some operations are invalid and were dropped; the others are shown for review.',\n invalidIds: ids => `Invalid IDs: ${ids}`,\n operation: (index, type, detail) => `- Operation ${index}${type ? ` (${type})` : ''}: ${detail}`,\n inside: 'An operation on a block inside a replaced or deleted block is dropped: the operation on the outer block applies. To change the inner block as well, write the change into the Markdown of the outer operation.',\n scoped: 'Use only IDs from the editing scope (see message); do not invent IDs.',\n unscoped: 'Use only IDs that appear in square brackets in the document; do not invent IDs.',\n again: tool => `Call ${tool} again with the complete, corrected list of all operations. Leave out operations that cannot be corrected.`,\n againPartial: tool => `Call ${tool} again with corrected versions of only the operations listed above; do not repeat the shown ones. Leave out operations that cannot be corrected.`,\n },\n shown: {\n shown: ops => `Shown in the document for review: ${ops}.`,\n none: 'None of the operations were shown.',\n dropped: count => `${count} operation(s) with invalid IDs were dropped; the user has been notified.`,\n decisions: 'The user accepts or rejects each change in the document; the decisions follow with a later message.',\n },\n feedback: decisions => `Decisions on your latest proposals: ${decisions}.`,\n },\n}\n\n/** How an outcome reads for the model, per locale; the chat shows the catalog's `ai.opTitle.*` texts. */\nexport const AGENT_OP_OUTCOME_TEXT: Record<Locale, Record<AgentOpOutcome, string>> = {\n de: AGENT_TEXTS.de.outcome,\n en: AGENT_TEXTS.en.outcome,\n}\n\n/** Text options of the model-facing functions: `locale` selects the language (default `de`). */\nexport interface AgentTextOptions { locale?: Locale }\n\n/** `update Block X`, `add nach Block X`, `add am Dokumentanfang`, `convert Block X → typedBlock:task` (`to` when known); English with `locale: 'en'`. */\nexport function agentOpSummary(op: { type: AgentOpType, target: string | null, to?: string }, { locale = 'de' }: AgentTextOptions = {}): string {\n const text = AGENT_TEXTS[locale].summary\n if (op.type === 'convert' && op.to) return text.convert(op.target, op.to)\n if (op.type !== 'add') return text.block(op.type, op.target)\n return op.target === null ? text.addStart : text.addAfter(op.target)\n}\n\n/**\n * Checks the raw `ops` of `edit_document` calls: every ID must exist and lie in the scope (`add` needs its `afterId`\n * key, `null` for the document start, and in a selection scope an `afterId` from the selection), fields must be\n * present, a `convert` target must be one of `targets`, a block is updated, converted or deleted at most once, and no\n * operation may point into a block (`lines.below`) that another operation replaces (`update`) or deletes: the\n * operation on the outer block wins. Several `add`s after the same block are fine; the client inserts them in the\n * order they were written. Returns the valid operations in order and the problems of the others; the problems'\n * `detail` is written in `context.locale` (default `de`).\n */\nexport function checkAgentOps(raw: readonly unknown[], context: AgentOpContext): { valid: ModelAgentOp[], problems: AgentOpProblem[] } {\n const accepted: { op: ModelAgentOp, index: number }[] = []\n const problems: AgentOpProblem[] = []\n const edited = new Set<string>()\n const text = AGENT_TEXTS[context.locale ?? 'de'].problem\n const known = (id: string) => context.lines.ids.has(id)\n\n raw.forEach((entry, i) => {\n const index = i + 1\n const value = (entry && typeof entry === 'object' ? entry : {}) as Record<string, unknown>\n const type = typeof value.type === 'string' ? value.type : null\n const problem = (reason: AgentOpProblemReason, id: string | null, detail: string) => problems.push({ index, type, id, reason, detail })\n const accept = (op: ModelAgentOp) => accepted.push({ op, index })\n\n if (index > AGENT_LIMITS.ops) return problem('limit', null, text.limit(AGENT_LIMITS.ops))\n if (!type || !(AGENT_OP_TYPES as readonly string[]).includes(type)) return problem('field', null, text.type(AGENT_OP_TYPES.join(', ')))\n\n const idField = type === 'add' ? 'afterId' : 'id'\n const rawId = value[idField]\n // `afterId: null` is the document start; a forgotten key must not become one.\n if (type === 'add' && rawId === undefined) {\n return problem('field', null, context.allowed ? text.afterIdMissingScoped : text.afterIdMissing)\n }\n if (type === 'add' && rawId === null) {\n if (context.allowed) return problem('scope', null, text.addAtStart)\n }\n else if (typeof rawId !== 'string' || !rawId.trim()) {\n return problem('field', null, text.idMissing(idField))\n }\n const id = typeof rawId === 'string' ? rawId.trim() : null\n if (id !== null) {\n if (!known(id)) return problem('unknown', id, text.unknownId(id))\n if (context.allowed && !context.allowed.has(id)) return problem('scope', id, text.outsideScope(id))\n }\n\n if (type === 'delete') {\n if (edited.has(id!)) return problem('duplicate', id, text.duplicate(id!))\n edited.add(id!)\n return accept({ type, id: id! })\n }\n\n if (type === 'convert') {\n const to = typeof value.to === 'string' ? value.to.trim() : ''\n if (!to) return problem('field', id, text.toMissing)\n if (!context.targets.has(to)) return problem('target', id, text.badTarget(to, [...context.targets].join(', ')))\n if (edited.has(id!)) return problem('duplicate', id, text.duplicate(id!))\n edited.add(id!)\n return accept({ type, id: id!, to })\n }\n\n const markdown = typeof value.markdown === 'string' ? stripBlockLineEcho(value.markdown, known).trim() : ''\n if (!markdown) return problem('field', id, type === 'update' ? text.markdownMissingUpdate : text.markdownMissing)\n if (markdown.length > AGENT_LIMITS.markdown) return problem('field', id, text.markdownTooLong(AGENT_LIMITS.markdown))\n if (type === 'add') return accept({ type, afterId: id, markdown })\n if (edited.has(id!)) return problem('duplicate', id, text.duplicate(id!))\n edited.add(id!)\n accept({ type: 'update', id: id!, markdown })\n })\n\n // An operation on a block inside another operation's block is dropped, naming the outermost operation that covers it.\n const owners = accepted.filter(({ op }) => op.type === 'update' || op.type === 'delete')\n const covering = ({ op }: typeof accepted[number]) => {\n const target = agentOpTarget(op)\n return target === null ? [] : owners.filter(owner => context.lines.below(agentOpTarget(owner.op)!).has(target))\n }\n const valid: ModelAgentOp[] = []\n for (const entry of accepted) {\n const cover = covering(entry)\n const owner = cover.find(candidate => !covering(candidate).length) ?? cover[0]\n if (!owner) {\n valid.push(entry.op)\n continue\n }\n const target = agentOpTarget(entry.op)!\n problems.push({\n index: entry.index,\n type: entry.op.type,\n id: target,\n reason: 'inside',\n detail: text.inside(target, agentOpTarget(owner.op)!, owner.index, owner.op.type === 'delete'),\n })\n }\n problems.sort((a, b) => a.index - b.index)\n return { valid, problems }\n}\n\n/** The problem for a tool call whose input was no object with the list `ops` (index 0), worded in `locale` (default `de`). */\nexport function agentUnreadableProblem({ locale = 'de' }: AgentTextOptions = {}): AgentOpProblem {\n return { index: 0, type: null, id: null, reason: 'field', detail: AGENT_TEXTS[locale].problem.unreadable }\n}\n\n/**\n * Tool result asking the model to call `tool` (default `edit_document`, the host's own tool name when it exposes the\n * operations under another one) again without the invalid operations' mistakes; worded in `locale` (default `de`).\n * By default nothing was applied and the model resends the whole list; with `partial` the host already shows the\n * valid operations, so the model resends only corrected versions of the listed ones.\n */\nexport function agentRetryMessage(\n problems: readonly AgentOpProblem[],\n scoped: boolean,\n { locale = 'de', tool = AGENT_TOOL, partial = false }: AgentTextOptions & { tool?: string, partial?: boolean } = {},\n): string {\n const text = AGENT_TEXTS[locale].retry\n const ids = [...new Set(problems.filter(p => p.reason !== 'inside').map(p => p.id).filter((id): id is string => !!id))]\n return [\n partial ? text.failedPartial : text.failed,\n ...(ids.length ? [text.invalidIds(ids.join(', '))] : []),\n ...problems.map(p => text.operation(p.index, p.type, p.detail)),\n ...(problems.some(p => p.reason === 'inside') ? [text.inside] : []),\n scoped ? text.scoped : text.unscoped,\n partial ? text.againPartial(tool) : text.again(tool),\n ].join('\\n')\n}\n\n/** Tool result of a past `edit_document` call: which operations were shown for review, and how many were dropped; worded in `locale` (default `de`). */\nexport function agentShownMessage(ops: readonly AgentOp[], dropped: number, { locale = 'de' }: AgentTextOptions = {}): string {\n const text = AGENT_TEXTS[locale].shown\n const lines = ops.length\n ? [text.shown(ops.map(op => `${op.op} (${agentOpSummary({ ...op, target: agentOpTarget(op) }, { locale })})`).join(', '))]\n : [text.none]\n if (dropped) lines.push(text.dropped(dropped))\n lines.push(text.decisions)\n return lines.join(' ')\n}\n\n/** „Entscheidungen zu deinen letzten Vorschlägen: op1 (update Block X) abgelehnt; …“ (English with `locale: 'en'`), or '' without feedback. */\nexport function agentFeedbackText(feedback: readonly AgentOpFeedback[], { locale = 'de' }: AgentTextOptions = {}): string {\n if (!feedback.length) return ''\n const outcome = AGENT_TEXTS[locale].outcome\n return AGENT_TEXTS[locale].feedback(feedback.map(f => `${f.op} (${agentOpSummary(f, { locale })}) ${outcome[f.outcome]}`).join('; '))\n}\n"],"mappings":"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"}
@@ -6,7 +6,7 @@
6
6
  * prompt describes all of that. Framework-free and free of ProseMirror: the browser writes the text, the server reads it.
7
7
  *
8
8
  * A line is `[<block id>] <prefix><text>`. The prefix carries list items (`- `, `1. `), quotes (`> `) and the nesting
9
- * of a block inside a Baustein or host block (two spaces per level). A Baustein is a header line, its body lines and a
9
+ * of a block inside a Typed block or host block (two spaces per level). A Typed block is a header line, its body lines and a
10
10
  * closing line `:::` without ID. Code blocks keep their own lines: the first one carries the ID, the others start at
11
11
  * the left edge, so their content can look like anything.
12
12
  */
@@ -16,7 +16,7 @@ export declare const TRUNCATED_LINE = "[…] (Rest des Dokuments gekürzt)";
16
16
  export declare function blockLine(id: string | null, prefix: string, text: string): string;
17
17
  /** `markdown` on one line: hard breaks and wrapped lines would start new "blocks". */
18
18
  export declare function singleBlockLine(markdown: string): string;
19
- /** The prefix of blocks inside the block whose lines carry `prefix` (the body of a Baustein or host block). */
19
+ /** The prefix of blocks inside the block whose lines carry `prefix` (the body of a Typed block or host block). */
20
20
  export declare function nestedLinePrefix(prefix: string): string;
21
21
  /** The prefix of the blocks of a quote. */
22
22
  export declare function quoteLinePrefix(prefix: string): string;
@@ -24,14 +24,14 @@ export declare function quoteLinePrefix(prefix: string): string;
24
24
  export declare function listLinePrefix(prefix: string, ordered: boolean, number: number): string;
25
25
  /** The prefix of the blocks of a list item after its first: they continue under its marker instead of repeating it. */
26
26
  export declare function continuedLinePrefix(prefix: string): string;
27
- /** One chrome row of a Baustein (`## title`, `> description`, `Tags: #a`) without its block marker, on one line. */
27
+ /** One chrome row of a Typed block (`## title`, `> description`, `Tags: #a`) without its block marker, on one line. */
28
28
  export declare function compositeChromePart(markdown: string): string;
29
29
  /**
30
- * The header text of a Baustein: `::: <kind> {meta}` (the meta as JSON only when it has entries), then every non-empty
30
+ * The header text of a Typed block: `::: <kind> {meta}` (the meta as JSON only when it has entries), then every non-empty
31
31
  * chrome part (title, description, tags) separated by ` | `.
32
32
  */
33
33
  export declare function compositeLineHeader(kind: string, meta: unknown, chrome: readonly string[]): string;
34
- /** The closing line of a Baustein whose header line is indented by `prefix`: no ID. */
34
+ /** The closing line of a Typed block whose header line is indented by `prefix`: no ID. */
35
35
  export declare function compositeLineClose(prefix: string): string;
36
36
  /** The block IDs of a document text and which blocks lie inside which. */
37
37
  export interface BlockLines {
@@ -54,7 +54,7 @@ export declare function readBlockLines(text: string): BlockLines;
54
54
  /**
55
55
  * Removes what a model echoes from the document lines into its Markdown: a `[<id>] ` prefix of a known block at the
56
56
  * start of a line (not inside a fenced code block of its own Markdown, which keeps lines that look like one), and the
57
- * indentation all non-blank lines share (lines echoed from a Baustein's body carry its indent, which would turn deeper
57
+ * indentation all non-blank lines share (lines echoed from a Typed block's body carry its indent, which would turn deeper
58
58
  * nested lines into indented code).
59
59
  */
60
60
  export declare function stripBlockLineEcho(markdown: string, known: (id: string) => boolean): string;
@@ -79,7 +79,7 @@ export declare const BLOCK_LINE_MARKERS: string;
79
79
  export declare const BLOCK_LINE_LIST_TEXT = "Listenpunkte und Zitate stehen nach der ID mit ihrem Zeichen; jeder Absatz darin hat eine eigene ID.";
80
80
  /** What the prompt says about the lines of a host block with block content (a callout). */
81
81
  export declare const BLOCK_LINE_HOST_TEXT: string;
82
- /** What the prompt says about the lines of a Baustein. */
82
+ /** What the prompt says about the lines of a Typed block. */
83
83
  export declare const BLOCK_LINE_COMPOSITE_TEXT: string;
84
84
  /** What the prompt says about the Markdown of an operation: no echo of the line prefix (`stripBlockLineEcho` removes it when it comes anyway). */
85
85
  export declare const BLOCK_LINE_ECHO_TEXT = "„markdown“ enthält nur den neuen Inhalt, ohne Block-ID und ohne das Listen- oder Zitatzeichen der Zeile.";