@ecsplico/editor 2.1.1 → 3.0.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 (701) hide show
  1. package/CHANGELOG.md +74 -1
  2. package/README.md +39 -156
  3. package/dist/adapters/comments/drizzle.d.ts +1 -1
  4. package/dist/adapters/comments/{client.js → rest-model.js} +3 -3
  5. package/dist/adapters/comments/rest-model.js.map +1 -0
  6. package/dist/adapters/comments/types.d.ts +2 -2
  7. package/dist/adapters/document-state.d.ts +23 -0
  8. package/dist/adapters/document-state.js +66 -0
  9. package/dist/adapters/document-state.js.map +1 -0
  10. package/dist/adapters/documents.js +14 -11
  11. package/dist/adapters/documents.js.map +1 -1
  12. package/dist/adapters/drizzle.d.ts +2 -2
  13. package/dist/adapters/drizzle.js +97 -88
  14. package/dist/adapters/drizzle.js.map +1 -1
  15. package/dist/adapters/forge.d.ts +12 -7
  16. package/dist/adapters/forge.js +38 -45
  17. package/dist/adapters/forge.js.map +1 -1
  18. package/dist/adapters/http.d.ts +20 -0
  19. package/dist/adapters/http.js +68 -0
  20. package/dist/adapters/http.js.map +1 -0
  21. package/dist/adapters/index.d.ts +5 -5
  22. package/dist/adapters/json.d.ts +3 -3
  23. package/dist/adapters/json.js +58 -49
  24. package/dist/adapters/json.js.map +1 -1
  25. package/dist/adapters/memory.d.ts +21 -0
  26. package/dist/adapters/memory.js +53 -0
  27. package/dist/adapters/memory.js.map +1 -0
  28. package/dist/adapters/nitro.d.ts +23 -20
  29. package/dist/adapters/nitro.js +58 -163
  30. package/dist/adapters/nitro.js.map +1 -1
  31. package/dist/adapters/react.d.ts +55 -0
  32. package/dist/adapters/react.js +209 -0
  33. package/dist/adapters/react.js.map +1 -0
  34. package/dist/adapters/shared.d.ts +15 -21
  35. package/dist/adapters/shared.js +10 -8
  36. package/dist/adapters/shared.js.map +1 -1
  37. package/dist/adapters/vue.d.ts +15 -30
  38. package/dist/adapters/vue.js +36 -87
  39. package/dist/adapters/vue.js.map +1 -1
  40. package/dist/code/CodeSurface.vue.d.ts +3 -3
  41. package/dist/config/index.d.ts +105 -0
  42. package/dist/config/index.js +95 -0
  43. package/dist/config/index.js.map +1 -0
  44. package/dist/core/abilities.js +1 -0
  45. package/dist/core/abilities.js.map +1 -1
  46. package/dist/{adapters/routes.js → core/api-routes.js} +5 -3
  47. package/dist/core/api-routes.js.map +1 -0
  48. package/dist/core/backend-capability.d.ts +7 -0
  49. package/dist/core/backend-capability.js +17 -0
  50. package/dist/core/backend-capability.js.map +1 -0
  51. package/dist/core/backend-types.d.ts +245 -0
  52. package/dist/core/backend-types.js +17 -0
  53. package/dist/core/backend-types.js.map +1 -0
  54. package/dist/core/backend.d.ts +108 -0
  55. package/dist/core/backend.js +14 -0
  56. package/dist/core/backend.js.map +1 -0
  57. package/dist/core/block-convert.d.ts +7 -5
  58. package/dist/core/block-convert.js +28 -5
  59. package/dist/core/block-convert.js.map +1 -1
  60. package/dist/core/command-types.d.ts +89 -0
  61. package/dist/core/commands.d.ts +40 -0
  62. package/dist/core/commands.js +151 -0
  63. package/dist/core/commands.js.map +1 -0
  64. package/dist/core/context.d.ts +17 -20
  65. package/dist/core/context.js +24 -21
  66. package/dist/core/context.js.map +1 -1
  67. package/dist/core/core-feature.d.ts +22 -7
  68. package/dist/core/core-feature.js +51 -18
  69. package/dist/core/core-feature.js.map +1 -1
  70. package/dist/core/define-editor.d.ts +4 -3
  71. package/dist/core/define-editor.js +14 -7
  72. package/dist/core/define-editor.js.map +1 -1
  73. package/dist/core/document-markdown.js +12 -3
  74. package/dist/core/document-markdown.js.map +1 -1
  75. package/dist/core/editor-ui.d.ts +8 -1
  76. package/dist/core/editor-ui.js +9 -8
  77. package/dist/core/editor-ui.js.map +1 -1
  78. package/dist/core/extension-points.d.ts +3 -15
  79. package/dist/core/feature-context.d.ts +8 -7
  80. package/dist/core/feature-context.js +12 -11
  81. package/dist/core/feature-context.js.map +1 -1
  82. package/dist/core/feature.d.ts +35 -19
  83. package/dist/core/feature.js.map +1 -1
  84. package/dist/core/fences.d.ts +2 -1
  85. package/dist/core/fences.js +3 -2
  86. package/dist/core/fences.js.map +1 -1
  87. package/dist/core/fetch-error.d.ts +1 -1
  88. package/dist/core/fetch-error.js +3 -1
  89. package/dist/core/fetch-error.js.map +1 -1
  90. package/dist/core/hash.d.ts +5 -0
  91. package/dist/core/hash.js +11 -0
  92. package/dist/core/hash.js.map +1 -0
  93. package/dist/core/http-backend.d.ts +11 -0
  94. package/dist/core/http-backend.js +195 -0
  95. package/dist/core/http-backend.js.map +1 -0
  96. package/dist/core/index.d.ts +14 -9
  97. package/dist/core/index.js +12 -9
  98. package/dist/core/palette.d.ts +48 -0
  99. package/dist/core/palette.js +95 -0
  100. package/dist/core/palette.js.map +1 -0
  101. package/dist/core/schema/abilities.d.ts +2 -1
  102. package/dist/core/schema/abilities.js +5 -1
  103. package/dist/core/schema/abilities.js.map +1 -1
  104. package/dist/core/schema/index.d.ts +11 -5
  105. package/dist/core/schema/index.js +13 -8
  106. package/dist/core/schema/index.js.map +1 -1
  107. package/dist/core/schema/mark-flags.d.ts +8 -1
  108. package/dist/core/schema/of-features.d.ts +13 -0
  109. package/dist/core/schema/of-features.js +14 -0
  110. package/dist/core/schema/of-features.js.map +1 -0
  111. package/dist/core/slash.d.ts +8 -6
  112. package/dist/core/slash.js +24 -16
  113. package/dist/core/slash.js.map +1 -1
  114. package/dist/core/surface-session.js +13 -5
  115. package/dist/core/surface-session.js.map +1 -1
  116. package/dist/core/toolbar-items.d.ts +10 -4
  117. package/dist/core/toolbar-items.js +269 -195
  118. package/dist/core/toolbar-items.js.map +1 -1
  119. package/dist/core/util.js +11 -0
  120. package/dist/core/util.js.map +1 -0
  121. package/dist/document/DocumentSurface.d.ts +1 -1
  122. package/dist/document/DocumentSurface.vue.d.ts +3 -3
  123. package/dist/features/ai/agent-op-review.d.ts +1 -1
  124. package/dist/features/ai/agent-op-review.js +1 -1
  125. package/dist/features/ai/agent-ops.js +1 -1
  126. package/dist/features/ai/ai-apply.d.ts +2 -2
  127. package/dist/features/ai/ai-apply.js +1 -1
  128. package/dist/features/ai/ai-review.js +1 -1
  129. package/dist/features/ai/ai-sse.d.ts +6 -6
  130. package/dist/features/ai/ai-sse.js +20 -63
  131. package/dist/features/ai/ai-sse.js.map +1 -1
  132. package/dist/features/ai/assistant.d.ts +8 -7
  133. package/dist/features/ai/assistant.js +3 -3
  134. package/dist/features/ai/assistant.js.map +1 -1
  135. package/dist/features/ai/block-actions.d.ts +3 -2
  136. package/dist/features/ai/block-actions.js +3 -2
  137. package/dist/features/ai/block-actions.js.map +1 -1
  138. package/dist/features/ai/components/AiSelectionMenu.js +1 -1
  139. package/dist/features/ai/components/DocumentChatAnswer.js +1 -1
  140. package/dist/features/ai/components/DocumentChatOps.vue.d.ts +1 -1
  141. package/dist/features/ai/components/SettingsModelProfiles.js +8 -8
  142. package/dist/features/ai/components/SettingsModelProfiles.js.map +1 -1
  143. package/dist/features/ai/document-chat-model.d.ts +8 -7
  144. package/dist/features/ai/document-chat-model.js +5 -5
  145. package/dist/features/ai/document-chat-model.js.map +1 -1
  146. package/dist/features/ai/document-chat.js +1 -1
  147. package/dist/features/ai/feature.js +27 -14
  148. package/dist/features/ai/feature.js.map +1 -1
  149. package/dist/features/ai/ghost-autocomplete.d.ts +7 -6
  150. package/dist/features/ai/ghost-autocomplete.js +6 -9
  151. package/dist/features/ai/ghost-autocomplete.js.map +1 -1
  152. package/dist/features/ai/index.d.ts +4 -3
  153. package/dist/features/ai/index.js +10 -10
  154. package/dist/features/ai/model-profiles.d.ts +5 -4
  155. package/dist/features/ai/model-profiles.js +2 -2
  156. package/dist/features/ai/model-profiles.js.map +1 -1
  157. package/dist/features/ai/protocol/block-lines.js +1 -1
  158. package/dist/features/ai/protocol/block-lines.js.map +1 -1
  159. package/dist/features/ai/protocol/chat.js +4 -1
  160. package/dist/features/ai/protocol/chat.js.map +1 -1
  161. package/dist/features/ai/protocol/index.d.ts +3 -2
  162. package/dist/features/ai/protocol/models.d.ts +2 -16
  163. package/dist/features/ai/protocol/models.js.map +1 -1
  164. package/dist/features/ai/rate-limit.d.ts +1 -1
  165. package/dist/features/ai/rate-limit.js +3 -1
  166. package/dist/features/ai/rate-limit.js.map +1 -1
  167. package/dist/features/ai/react/AiSelectionMenu.js +2 -2
  168. package/dist/features/ai/react/AiSidebar.js +4 -4
  169. package/dist/features/ai/react/DocumentChatAnswer.js +1 -1
  170. package/dist/features/ai/react/DocumentChatOps.d.ts +1 -1
  171. package/dist/features/ai/react/DocumentChatOps.js +1 -1
  172. package/dist/features/ai/react/SettingsModelProfiles.js +8 -10
  173. package/dist/features/ai/react/SettingsModelProfiles.js.map +1 -1
  174. package/dist/features/ai/react/use-ai-assistant.d.ts +1 -1
  175. package/dist/features/ai/react/use-ai-assistant.js +3 -3
  176. package/dist/features/ai/react/use-ai-assistant.js.map +1 -1
  177. package/dist/features/ai/react/use-document-chat.js +2 -2
  178. package/dist/features/ai/react/use-document-chat.js.map +1 -1
  179. package/dist/features/ai/react/use-model-profiles.d.ts +2 -1
  180. package/dist/features/ai/selection-flow.d.ts +1 -1
  181. package/dist/features/ai/selection-flow.js +1 -1
  182. package/dist/features/ai/sidebar-flow.d.ts +1 -1
  183. package/dist/features/ai/sidebar-flow.js +1 -1
  184. package/dist/features/ai/use-ai-assistant.d.ts +1 -1
  185. package/dist/features/ai/use-ai-assistant.js +3 -3
  186. package/dist/features/ai/use-ai-assistant.js.map +1 -1
  187. package/dist/features/ai/use-document-chat.js +2 -2
  188. package/dist/features/ai/use-document-chat.js.map +1 -1
  189. package/dist/features/ai/use-model-profiles.d.ts +2 -1
  190. package/dist/features/authors/attribution.d.ts +1 -1
  191. package/dist/features/authors/feature.js +12 -11
  192. package/dist/features/authors/feature.js.map +1 -1
  193. package/dist/features/block-ui/block-actions.d.ts +22 -1
  194. package/dist/features/block-ui/block-actions.js +26 -2
  195. package/dist/features/block-ui/block-actions.js.map +1 -1
  196. package/dist/features/block-ui/components/BlockActionsOverlay.js +33 -4
  197. package/dist/features/block-ui/components/BlockActionsOverlay.js.map +1 -1
  198. package/dist/features/block-ui/components/BlockActionsOverlay.vue.d.ts +4 -0
  199. package/dist/features/block-ui/components/BlockUi.js +1 -1
  200. package/dist/features/block-ui/feature.js +1 -0
  201. package/dist/features/block-ui/feature.js.map +1 -1
  202. package/dist/features/block-ui/index.d.ts +2 -2
  203. package/dist/features/block-ui/index.js +2 -2
  204. package/dist/features/block-ui/react/BlockActionsOverlay.d.ts +4 -0
  205. package/dist/features/block-ui/react/BlockActionsOverlay.js +38 -12
  206. package/dist/features/block-ui/react/BlockActionsOverlay.js.map +1 -1
  207. package/dist/features/block-ui/react/BlockUi.js +1 -1
  208. package/dist/features/collab/anchor-resolver.js +1 -1
  209. package/dist/features/collab/feature.js +2 -0
  210. package/dist/features/collab/feature.js.map +1 -1
  211. package/dist/features/comments/components/CommentThreadView.vue.d.ts +2 -1
  212. package/dist/features/comments/feature.js +12 -11
  213. package/dist/features/comments/feature.js.map +1 -1
  214. package/dist/features/comments/index.d.ts +3 -2
  215. package/dist/features/comments/index.js +1 -1
  216. package/dist/features/comments/margin-layout.d.ts +3 -2
  217. package/dist/features/comments/model.d.ts +3 -67
  218. package/dist/features/comments/model.js +2 -2
  219. package/dist/features/comments/model.js.map +1 -1
  220. package/dist/features/comments/react/CommentThreadView.d.ts +3 -2
  221. package/dist/features/comments/react/use-comments.d.ts +2 -1
  222. package/dist/features/comments/react.d.ts +1 -1
  223. package/dist/features/comments/schema.d.ts +2 -52
  224. package/dist/features/comments/schema.js.map +1 -1
  225. package/dist/features/comments/snapshot-equality.js.map +1 -1
  226. package/dist/features/comments/use-comments.d.ts +3 -2
  227. package/dist/features/comments/vue.d.ts +1 -1
  228. package/dist/features/composites/accepted-children.d.ts +1 -0
  229. package/dist/features/composites/accepted-children.js +16 -1
  230. package/dist/features/composites/accepted-children.js.map +1 -1
  231. package/dist/features/composites/ai-brief.js +31 -0
  232. package/dist/features/composites/ai-brief.js.map +1 -1
  233. package/dist/features/composites/bibliography-command.d.ts +11 -0
  234. package/dist/features/composites/bibliography-form.js +90 -0
  235. package/dist/features/composites/bibliography-form.js.map +1 -0
  236. package/dist/features/composites/bibliography.d.ts +33 -0
  237. package/dist/features/composites/bibliography.js +120 -0
  238. package/dist/features/composites/bibliography.js.map +1 -0
  239. package/dist/features/composites/components/BibliographyEditor.js +261 -0
  240. package/dist/features/composites/components/BibliographyEditor.js.map +1 -0
  241. package/dist/features/composites/components/CompositeChrome.js +75 -26
  242. package/dist/features/composites/components/CompositeChrome.js.map +1 -1
  243. package/dist/features/composites/components/CompositeDetails.js +46 -11
  244. package/dist/features/composites/components/CompositeDetails.js.map +1 -1
  245. package/dist/features/composites/components/CompositeDetails.vue.d.ts +2 -1
  246. package/dist/features/composites/components/CompositeFieldEditor.js +37 -4
  247. package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
  248. package/dist/features/composites/components/CompositeInspector.js +17 -5
  249. package/dist/features/composites/components/CompositeInspector.js.map +1 -1
  250. package/dist/features/composites/components/CompositeTable.js +13 -4
  251. package/dist/features/composites/components/CompositeTable.js.map +1 -1
  252. package/dist/features/composites/components/CompositeTagsEditor.js +1 -1
  253. package/dist/features/composites/components/CompositeView.js +11 -1
  254. package/dist/features/composites/components/CompositeView.js.map +1 -1
  255. package/dist/features/composites/components/DerivationBadge.js +103 -0
  256. package/dist/features/composites/components/DerivationBadge.js.map +1 -0
  257. package/dist/features/composites/components/ReferenceFieldSelect.js +60 -0
  258. package/dist/features/composites/components/ReferenceFieldSelect.js.map +1 -0
  259. package/dist/features/composites/components/ReferenceView.js +122 -0
  260. package/dist/features/composites/components/ReferenceView.js.map +1 -0
  261. package/dist/features/composites/components/ReferenceView.vue.d.ts +96 -0
  262. package/dist/features/composites/components/SettingsEditingTab.js +1 -1
  263. package/dist/features/composites/convert.js +2 -2
  264. package/dist/features/composites/convert.js.map +1 -1
  265. package/dist/features/composites/derivation.d.ts +61 -0
  266. package/dist/features/composites/derivation.js +98 -0
  267. package/dist/features/composites/derivation.js.map +1 -0
  268. package/dist/features/composites/derived-chrome.js +69 -0
  269. package/dist/features/composites/derived-chrome.js.map +1 -0
  270. package/dist/features/composites/feature.js +159 -109
  271. package/dist/features/composites/feature.js.map +1 -1
  272. package/dist/features/composites/fences.d.ts +4 -3
  273. package/dist/features/composites/fences.js +51 -7
  274. package/dist/features/composites/fences.js.map +1 -1
  275. package/dist/features/composites/index.d.ts +12 -3
  276. package/dist/features/composites/index.js +15 -6
  277. package/dist/features/composites/inspector-model.d.ts +4 -1
  278. package/dist/features/composites/inspector-model.js +8 -4
  279. package/dist/features/composites/inspector-model.js.map +1 -1
  280. package/dist/features/composites/kinds.d.ts +8 -1
  281. package/dist/features/composites/kinds.js +145 -6
  282. package/dist/features/composites/kinds.js.map +1 -1
  283. package/dist/features/composites/legacy.d.ts +4 -1
  284. package/dist/features/composites/legacy.js +56 -1
  285. package/dist/features/composites/legacy.js.map +1 -1
  286. package/dist/features/composites/meta-display.js +40 -1
  287. package/dist/features/composites/meta-display.js.map +1 -1
  288. package/dist/features/composites/meta-keys.d.ts +7 -0
  289. package/dist/features/composites/meta-keys.js +21 -0
  290. package/dist/features/composites/meta-keys.js.map +1 -0
  291. package/dist/features/composites/node-views.d.ts +6 -3
  292. package/dist/features/composites/node-views.js +7 -3
  293. package/dist/features/composites/node-views.js.map +1 -1
  294. package/dist/features/composites/nodes.d.ts +6 -1
  295. package/dist/features/composites/nodes.js +33 -7
  296. package/dist/features/composites/nodes.js.map +1 -1
  297. package/dist/features/composites/react/BibliographyEditor.js +229 -0
  298. package/dist/features/composites/react/BibliographyEditor.js.map +1 -0
  299. package/dist/features/composites/react/CompositeChrome.js +65 -17
  300. package/dist/features/composites/react/CompositeChrome.js.map +1 -1
  301. package/dist/features/composites/react/CompositeDetails.d.ts +2 -1
  302. package/dist/features/composites/react/CompositeDetails.js +45 -6
  303. package/dist/features/composites/react/CompositeDetails.js.map +1 -1
  304. package/dist/features/composites/react/CompositeFieldEditor.d.ts +1 -1
  305. package/dist/features/composites/react/CompositeFieldEditor.js +24 -1
  306. package/dist/features/composites/react/CompositeFieldEditor.js.map +1 -1
  307. package/dist/features/composites/react/CompositeInspector.js +11 -5
  308. package/dist/features/composites/react/CompositeInspector.js.map +1 -1
  309. package/dist/features/composites/react/CompositeStatusMenu.js +1 -1
  310. package/dist/features/composites/react/CompositeSummaryEditor.js +1 -1
  311. package/dist/features/composites/react/CompositeTable.js +16 -2
  312. package/dist/features/composites/react/CompositeTable.js.map +1 -1
  313. package/dist/features/composites/react/CompositeTagsEditor.js +2 -2
  314. package/dist/features/composites/react/CompositeView.js +6 -1
  315. package/dist/features/composites/react/CompositeView.js.map +1 -1
  316. package/dist/features/composites/react/DerivationBadge.js +116 -0
  317. package/dist/features/composites/react/DerivationBadge.js.map +1 -0
  318. package/dist/features/composites/react/ReferenceFieldSelect.js +52 -0
  319. package/dist/features/composites/react/ReferenceFieldSelect.js.map +1 -0
  320. package/dist/features/composites/react/ReferenceView.d.ts +11 -0
  321. package/dist/features/composites/react/ReferenceView.js +115 -0
  322. package/dist/features/composites/react/ReferenceView.js.map +1 -0
  323. package/dist/features/composites/react/SettingsEditingTab.js +2 -2
  324. package/dist/features/composites/react.d.ts +2 -1
  325. package/dist/features/composites/react.js +7 -3
  326. package/dist/features/composites/react.js.map +1 -1
  327. package/dist/features/composites/reference-ai.js +16 -0
  328. package/dist/features/composites/reference-ai.js.map +1 -0
  329. package/dist/features/composites/reference-label.d.ts +19 -0
  330. package/dist/features/composites/reference-label.js +58 -0
  331. package/dist/features/composites/reference-label.js.map +1 -0
  332. package/dist/features/composites/reference-suggestion.d.ts +10 -0
  333. package/dist/features/composites/reference-suggestion.js +41 -0
  334. package/dist/features/composites/reference-suggestion.js.map +1 -0
  335. package/dist/features/composites/reference-text.d.ts +18 -0
  336. package/dist/features/composites/reference-text.js +89 -0
  337. package/dist/features/composites/reference-text.js.map +1 -0
  338. package/dist/features/composites/reference.d.ts +44 -0
  339. package/dist/features/composites/reference.js +148 -0
  340. package/dist/features/composites/reference.js.map +1 -0
  341. package/dist/features/composites/reveal-source.d.ts +32 -0
  342. package/dist/features/composites/reveal-source.js +89 -0
  343. package/dist/features/composites/reveal-source.js.map +1 -0
  344. package/dist/features/composites/rows.d.ts +21 -2
  345. package/dist/features/composites/rows.js +63 -9
  346. package/dist/features/composites/rows.js.map +1 -1
  347. package/dist/features/composites/schema.d.ts +9 -3
  348. package/dist/features/composites/schema.js +11 -4
  349. package/dist/features/composites/schema.js.map +1 -1
  350. package/dist/features/composites/table-model.js +12 -21
  351. package/dist/features/composites/table-model.js.map +1 -1
  352. package/dist/features/composites/vue.d.ts +3 -2
  353. package/dist/features/composites/vue.js +8 -4
  354. package/dist/features/composites/vue.js.map +1 -1
  355. package/dist/features/media/assets.d.ts +2 -0
  356. package/dist/features/media/assets.js +3 -2
  357. package/dist/features/media/assets.js.map +1 -1
  358. package/dist/features/media/components/FileView.js +13 -4
  359. package/dist/features/media/components/FileView.js.map +1 -1
  360. package/dist/features/media/feature.d.ts +3 -3
  361. package/dist/features/media/feature.js +21 -28
  362. package/dist/features/media/feature.js.map +1 -1
  363. package/dist/features/media/file-import.js +2 -2
  364. package/dist/features/media/file-import.js.map +1 -1
  365. package/dist/features/media/index.d.ts +2 -2
  366. package/dist/features/media/index.js +2 -2
  367. package/dist/features/media/react/FileView.js +19 -2
  368. package/dist/features/media/react/FileView.js.map +1 -1
  369. package/dist/features/media/schema.d.ts +8 -0
  370. package/dist/features/media/schema.js +126 -11
  371. package/dist/features/media/schema.js.map +1 -1
  372. package/dist/features/media/upload.d.ts +16 -14
  373. package/dist/features/media/upload.js +13 -19
  374. package/dist/features/media/upload.js.map +1 -1
  375. package/dist/features/mentions/index.d.ts +4 -3
  376. package/dist/features/mentions/index.js +4 -1
  377. package/dist/features/mentions/index.js.map +1 -1
  378. package/dist/features/mentions/mention-text.d.ts +1 -1
  379. package/dist/features/mentions/mention-text.js.map +1 -1
  380. package/dist/features/mentions/mention.d.ts +0 -6
  381. package/dist/features/mentions/mention.js.map +1 -1
  382. package/dist/features/mentions/metadata-defaults.d.ts +2 -2
  383. package/dist/features/mentions/metadata-defaults.js +3 -9
  384. package/dist/features/mentions/metadata-defaults.js.map +1 -1
  385. package/dist/features/mentions/schema.d.ts +2 -1
  386. package/dist/features/mentions/schema.js.map +1 -1
  387. package/dist/features/tables/feature.d.ts +2 -1
  388. package/dist/features/tables/feature.js +90 -70
  389. package/dist/features/tables/feature.js.map +1 -1
  390. package/dist/features/themes/components/SettingsAppearanceTab.js +6 -9
  391. package/dist/features/themes/components/SettingsAppearanceTab.js.map +1 -1
  392. package/dist/features/themes/feature.js +2 -0
  393. package/dist/features/themes/feature.js.map +1 -1
  394. package/dist/features/themes/index.d.ts +2 -1
  395. package/dist/features/themes/react/SettingsAppearanceTab.js +7 -10
  396. package/dist/features/themes/react/SettingsAppearanceTab.js.map +1 -1
  397. package/dist/features/themes/schema.d.ts +2 -6
  398. package/dist/features/themes/schema.js.map +1 -1
  399. package/dist/features/themes/theme-runtime.d.ts +1 -1
  400. package/dist/features/themes/theme-runtime.js +4 -2
  401. package/dist/features/themes/theme-runtime.js.map +1 -1
  402. package/dist/features/transcript/TranscriptSegmentView.js +48 -28
  403. package/dist/features/transcript/TranscriptSegmentView.js.map +1 -1
  404. package/dist/features/transcript/feature.js +21 -19
  405. package/dist/features/transcript/feature.js.map +1 -1
  406. package/dist/features/transcript/react/TranscriptSegmentView.js +55 -36
  407. package/dist/features/transcript/react/TranscriptSegmentView.js.map +1 -1
  408. package/dist/features/transcript/segment-node.d.ts +2 -0
  409. package/dist/features/transcript/segment-node.js +35 -7
  410. package/dist/features/transcript/segment-node.js.map +1 -1
  411. package/dist/i18n/de/composites.js +91 -1
  412. package/dist/i18n/de/composites.js.map +1 -1
  413. package/dist/i18n/de/integrations.js +49 -8
  414. package/dist/i18n/de/integrations.js.map +1 -1
  415. package/dist/i18n/de/media.js +0 -1
  416. package/dist/i18n/de/media.js.map +1 -1
  417. package/dist/i18n/de/palette.js +22 -0
  418. package/dist/i18n/de/palette.js.map +1 -0
  419. package/dist/i18n/de/tables.js +0 -1
  420. package/dist/i18n/de/tables.js.map +1 -1
  421. package/dist/i18n/de/transcript.js +2 -1
  422. package/dist/i18n/de/transcript.js.map +1 -1
  423. package/dist/i18n/de/tree.js +3 -0
  424. package/dist/i18n/de/tree.js.map +1 -1
  425. package/dist/i18n/de.d.ts +157 -11
  426. package/dist/i18n/de.js +3 -1
  427. package/dist/i18n/de.js.map +1 -1
  428. package/dist/i18n/en/composites.js +89 -1
  429. package/dist/i18n/en/composites.js.map +1 -1
  430. package/dist/i18n/en/integrations.js +49 -8
  431. package/dist/i18n/en/integrations.js.map +1 -1
  432. package/dist/i18n/en/media.js +0 -1
  433. package/dist/i18n/en/media.js.map +1 -1
  434. package/dist/i18n/en/palette.js +22 -0
  435. package/dist/i18n/en/palette.js.map +1 -0
  436. package/dist/i18n/en/tables.js +0 -1
  437. package/dist/i18n/en/tables.js.map +1 -1
  438. package/dist/i18n/en/transcript.js +2 -1
  439. package/dist/i18n/en/transcript.js.map +1 -1
  440. package/dist/i18n/en/tree.js +3 -0
  441. package/dist/i18n/en/tree.js.map +1 -1
  442. package/dist/i18n/en.js +3 -1
  443. package/dist/i18n/en.js.map +1 -1
  444. package/dist/index.d.ts +4 -3
  445. package/dist/integrations/composite-ai/bibliography-fetch.d.ts +31 -0
  446. package/dist/integrations/composite-ai/bibliography-fetch.js +159 -0
  447. package/dist/integrations/composite-ai/bibliography-fetch.js.map +1 -0
  448. package/dist/integrations/composite-ai/composite-fill.d.ts +30 -8
  449. package/dist/integrations/composite-ai/composite-fill.js +97 -56
  450. package/dist/integrations/composite-ai/composite-fill.js.map +1 -1
  451. package/dist/integrations/composite-ai/composite-summary.d.ts +4 -12
  452. package/dist/integrations/composite-ai/composite-summary.js +7 -26
  453. package/dist/integrations/composite-ai/composite-summary.js.map +1 -1
  454. package/dist/integrations/composite-ai/derive.d.ts +29 -0
  455. package/dist/integrations/composite-ai/derive.js +173 -0
  456. package/dist/integrations/composite-ai/derive.js.map +1 -0
  457. package/dist/integrations/composite-ai/index.d.ts +11 -7
  458. package/dist/integrations/composite-ai/index.js +72 -14
  459. package/dist/integrations/composite-ai/index.js.map +1 -1
  460. package/dist/integrations/composite-ai/rendition.d.ts +45 -0
  461. package/dist/integrations/composite-ai/rendition.js +314 -0
  462. package/dist/integrations/composite-ai/rendition.js.map +1 -0
  463. package/dist/integrations/composite-media/index.d.ts +7 -5
  464. package/dist/integrations/composite-media/index.js +86 -13
  465. package/dist/integrations/composite-media/index.js.map +1 -1
  466. package/dist/integrations/transcript-ai/index.d.ts +1 -1
  467. package/dist/integrations/transcript-ai/index.js +5 -2
  468. package/dist/integrations/transcript-ai/index.js.map +1 -1
  469. package/dist/integrations/transcript-ai/protocol.d.ts +2 -12
  470. package/dist/integrations/transcript-ai/protocol.js +0 -2
  471. package/dist/integrations/transcript-ai/protocol.js.map +1 -1
  472. package/dist/integrations/transcript-ai/transcript-cleanup.d.ts +5 -5
  473. package/dist/integrations/transcript-ai/transcript-cleanup.js +7 -10
  474. package/dist/integrations/transcript-ai/transcript-cleanup.js.map +1 -1
  475. package/dist/markdown/MarkdownSurface.vue.d.ts +10 -9
  476. package/dist/markdown/MarkdownSurface2.js +3 -6
  477. package/dist/markdown/MarkdownSurface2.js.map +1 -1
  478. package/dist/markdown/document.js +1 -1
  479. package/dist/markdown/source-mode.d.ts +1 -1
  480. package/dist/nuxt/module.d.ts +1402 -54
  481. package/dist/nuxt/module.js +6 -49
  482. package/dist/nuxt/module.js.map +1 -1
  483. package/dist/nuxt/runtime/install-context.d.ts +7 -3
  484. package/dist/nuxt/runtime/install-context.js +14 -8
  485. package/dist/nuxt/runtime/install-context.js.map +1 -1
  486. package/dist/nuxt/runtime/plugins/editor-context-nuxt-ui.client.ts +2 -2
  487. package/dist/nuxt/runtime/server/plugins/editor-server.js +20 -12
  488. package/dist/nuxt/runtime/server/plugins/editor-server.js.map +1 -1
  489. package/dist/presets/compose.d.ts +94 -0
  490. package/dist/presets/compose.js +164 -0
  491. package/dist/presets/compose.js.map +1 -0
  492. package/dist/react/AdvancedEditor.d.ts +15 -15
  493. package/dist/react/AdvancedEditor.js +15 -13
  494. package/dist/react/AdvancedEditor.js.map +1 -1
  495. package/dist/react/EditorCommandPalette.d.ts +13 -0
  496. package/dist/react/EditorCommandPalette.js +118 -0
  497. package/dist/react/EditorCommandPalette.js.map +1 -0
  498. package/dist/react/EditorSettingsModal.d.ts +5 -5
  499. package/dist/react/EditorSettingsModal.js +7 -4
  500. package/dist/react/EditorSettingsModal.js.map +1 -1
  501. package/dist/react/EditorSettingsPanel.d.ts +7 -7
  502. package/dist/react/EditorSettingsPanel.js +8 -5
  503. package/dist/react/EditorSettingsPanel.js.map +1 -1
  504. package/dist/react/EditorSurface.d.ts +7 -7
  505. package/dist/react/EditorSurface.js +10 -6
  506. package/dist/react/EditorSurface.js.map +1 -1
  507. package/dist/react/EditorToolbar.d.ts +4 -6
  508. package/dist/react/EditorToolbar.js +29 -37
  509. package/dist/react/EditorToolbar.js.map +1 -1
  510. package/dist/react/SimpleEditor.d.ts +22 -23
  511. package/dist/react/SimpleEditor.js +21 -7
  512. package/dist/react/SimpleEditor.js.map +1 -1
  513. package/dist/react/advanced.d.ts +4 -3
  514. package/dist/react/advanced.js +2 -2
  515. package/dist/react/compose.d.ts +20 -0
  516. package/dist/react/compose.js +49 -0
  517. package/dist/react/compose.js.map +1 -0
  518. package/dist/react/composed-surface.d.ts +39 -0
  519. package/dist/react/composed-surface.js +71 -0
  520. package/dist/react/composed-surface.js.map +1 -0
  521. package/dist/react/context.js +6 -2
  522. package/dist/react/context.js.map +1 -1
  523. package/dist/react/index.d.ts +2 -1
  524. package/dist/react/index.js +2 -1
  525. package/dist/react/key-labels.js +15 -0
  526. package/dist/react/key-labels.js.map +1 -0
  527. package/dist/react/settings.d.ts +1 -1
  528. package/dist/react/simple.d.ts +2 -2
  529. package/dist/react/ui/command.js +36 -1
  530. package/dist/react/ui/command.js.map +1 -1
  531. package/dist/schema/advanced.d.ts +6 -6
  532. package/dist/schema/advanced.js +26 -29
  533. package/dist/schema/advanced.js.map +1 -1
  534. package/dist/server/ai.d.ts +5 -16
  535. package/dist/server/ai.js.map +1 -1
  536. package/dist/server/auth.d.ts +9 -0
  537. package/dist/server/collab-state.d.ts +1 -1
  538. package/dist/server/collab-state.js.map +1 -1
  539. package/dist/server/collab.d.ts +13 -13
  540. package/dist/server/collab.js +34 -18
  541. package/dist/server/collab.js.map +1 -1
  542. package/dist/server/crossref.js +78 -0
  543. package/dist/server/crossref.js.map +1 -0
  544. package/dist/server/errors.d.ts +1 -1
  545. package/dist/server/errors.js +1 -1
  546. package/dist/server/errors.js.map +1 -1
  547. package/dist/server/extract.js +308 -0
  548. package/dist/server/extract.js.map +1 -0
  549. package/dist/{nuxt/runtime/server/utils/editor-route.js → server/h3.js} +8 -16
  550. package/dist/server/h3.js.map +1 -0
  551. package/dist/server/handlers/ai.d.ts +30 -9
  552. package/dist/server/handlers/ai.js +170 -36
  553. package/dist/server/handlers/ai.js.map +1 -1
  554. package/dist/server/handlers/context.d.ts +12 -5
  555. package/dist/server/handlers/context.js +10 -4
  556. package/dist/server/handlers/context.js.map +1 -1
  557. package/dist/server/handlers/editor.d.ts +19 -13
  558. package/dist/server/handlers/editor.js +49 -38
  559. package/dist/server/handlers/editor.js.map +1 -1
  560. package/dist/server/handlers/index.d.ts +4 -4
  561. package/dist/server/handlers/index.js +4 -4
  562. package/dist/server/host.d.ts +16 -25
  563. package/dist/server/host.js +58 -41
  564. package/dist/server/host.js.map +1 -1
  565. package/dist/server/index.d.ts +6 -4
  566. package/dist/server/index.js +3 -2
  567. package/dist/server/pdf.js +97 -0
  568. package/dist/server/pdf.js.map +1 -0
  569. package/dist/server/{adapter.d.ts → ports.d.ts} +81 -30
  570. package/dist/server/ports.js +29 -0
  571. package/dist/server/ports.js.map +1 -0
  572. package/dist/server/routes.js +144 -0
  573. package/dist/server/routes.js.map +1 -0
  574. package/dist/settings/index.d.ts +1 -1
  575. package/dist/settings/index.js.map +1 -1
  576. package/dist/styles/composites.css +25 -0
  577. package/dist/tree/DocumentTree.js +56 -29
  578. package/dist/tree/DocumentTree.js.map +1 -1
  579. package/dist/tree/react/DocumentTree.js +23 -0
  580. package/dist/tree/react/DocumentTree.js.map +1 -1
  581. package/dist/tree/tree-host.js +1 -1
  582. package/dist/vue/AdvancedEditor.js +30 -9
  583. package/dist/vue/AdvancedEditor.js.map +1 -1
  584. package/dist/vue/AdvancedEditor.vue.d.ts +32 -12
  585. package/dist/vue/SimpleEditor.js +62 -16
  586. package/dist/vue/SimpleEditor.js.map +1 -1
  587. package/dist/vue/SimpleEditor.vue.d.ts +37 -7
  588. package/dist/vue/advanced.d.ts +3 -2
  589. package/dist/vue/advanced.js +2 -2
  590. package/dist/vue/components/EditorCommandPalette.js +91 -0
  591. package/dist/vue/components/EditorCommandPalette.js.map +1 -0
  592. package/dist/vue/components/EditorCommandPalette.vue.d.ts +15 -0
  593. package/dist/vue/components/EditorSettingsModal.js +10 -6
  594. package/dist/vue/components/EditorSettingsModal.js.map +1 -1
  595. package/dist/vue/components/EditorSettingsModal.vue.d.ts +4 -4
  596. package/dist/vue/components/EditorSettingsPanel.js +10 -6
  597. package/dist/vue/components/EditorSettingsPanel.js.map +1 -1
  598. package/dist/vue/components/EditorSettingsPanel.vue.d.ts +6 -6
  599. package/dist/vue/components/EditorSurface.js +11 -6
  600. package/dist/vue/components/EditorSurface.js.map +1 -1
  601. package/dist/vue/components/EditorSurface.vue.d.ts +11 -11
  602. package/dist/vue/components/EditorToolbar.js +41 -49
  603. package/dist/vue/components/EditorToolbar.js.map +1 -1
  604. package/dist/vue/components/EditorToolbar.vue.d.ts +2 -4
  605. package/dist/vue/compose.d.ts +17 -0
  606. package/dist/vue/compose.js +51 -0
  607. package/dist/vue/compose.js.map +1 -0
  608. package/dist/vue/context-key.d.ts +6 -0
  609. package/dist/vue/context-key.js +6 -0
  610. package/dist/vue/context-key.js.map +1 -0
  611. package/dist/vue/context.d.ts +8 -6
  612. package/dist/vue/context.js +6 -5
  613. package/dist/vue/context.js.map +1 -1
  614. package/dist/vue/index.d.ts +10 -8
  615. package/dist/vue/index.js +10 -8
  616. package/dist/vue/kit/index.d.ts +2 -2
  617. package/dist/vue/kit/nuxt-ui.js +23 -0
  618. package/dist/vue/kit/nuxt-ui.js.map +1 -1
  619. package/dist/vue/kit/types.d.ts +40 -1
  620. package/package.json +30 -16
  621. package/dist/adapters/comments/client.d.ts +0 -64
  622. package/dist/adapters/comments/client.js.map +0 -1
  623. package/dist/adapters/routes.js.map +0 -1
  624. package/dist/core/toolbar.d.ts +0 -74
  625. package/dist/core/toolbar.js +0 -45
  626. package/dist/core/toolbar.js.map +0 -1
  627. package/dist/integrations/composite-ai/document-transcribe.d.ts +0 -14
  628. package/dist/integrations/composite-ai/document-transcribe.js +0 -89
  629. package/dist/integrations/composite-ai/document-transcribe.js.map +0 -1
  630. package/dist/nuxt/runtime/server/api/ai/chat.post.d.ts +0 -5
  631. package/dist/nuxt/runtime/server/api/ai/chat.post.js +0 -8
  632. package/dist/nuxt/runtime/server/api/ai/chat.post.js.map +0 -1
  633. package/dist/nuxt/runtime/server/api/ai/complete.post.d.ts +0 -5
  634. package/dist/nuxt/runtime/server/api/ai/complete.post.js +0 -8
  635. package/dist/nuxt/runtime/server/api/ai/complete.post.js.map +0 -1
  636. package/dist/nuxt/runtime/server/api/ai/generate.post.d.ts +0 -5
  637. package/dist/nuxt/runtime/server/api/ai/generate.post.js +0 -8
  638. package/dist/nuxt/runtime/server/api/ai/generate.post.js.map +0 -1
  639. package/dist/nuxt/runtime/server/api/ai/models.get.d.ts +0 -5
  640. package/dist/nuxt/runtime/server/api/ai/models.get.js +0 -8
  641. package/dist/nuxt/runtime/server/api/ai/models.get.js.map +0 -1
  642. package/dist/nuxt/runtime/server/api/ai/transcribe.post.d.ts +0 -5
  643. package/dist/nuxt/runtime/server/api/ai/transcribe.post.js +0 -8
  644. package/dist/nuxt/runtime/server/api/ai/transcribe.post.js.map +0 -1
  645. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.d.ts +0 -5
  646. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js +0 -8
  647. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js.map +0 -1
  648. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.d.ts +0 -5
  649. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js +0 -8
  650. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js.map +0 -1
  651. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.d.ts +0 -5
  652. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js +0 -8
  653. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js.map +0 -1
  654. package/dist/nuxt/runtime/server/api/editor/settings.get.d.ts +0 -5
  655. package/dist/nuxt/runtime/server/api/editor/settings.get.js +0 -8
  656. package/dist/nuxt/runtime/server/api/editor/settings.get.js.map +0 -1
  657. package/dist/nuxt/runtime/server/api/editor/settings.put.d.ts +0 -5
  658. package/dist/nuxt/runtime/server/api/editor/settings.put.js +0 -8
  659. package/dist/nuxt/runtime/server/api/editor/settings.put.js.map +0 -1
  660. package/dist/nuxt/runtime/server/api/editor/tags.get.d.ts +0 -5
  661. package/dist/nuxt/runtime/server/api/editor/tags.get.js +0 -8
  662. package/dist/nuxt/runtime/server/api/editor/tags.get.js.map +0 -1
  663. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.d.ts +0 -5
  664. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js +0 -8
  665. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js.map +0 -1
  666. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.d.ts +0 -5
  667. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js +0 -8
  668. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js.map +0 -1
  669. package/dist/nuxt/runtime/server/api/editor/themes/index.get.d.ts +0 -5
  670. package/dist/nuxt/runtime/server/api/editor/themes/index.get.js +0 -8
  671. package/dist/nuxt/runtime/server/api/editor/themes/index.get.js.map +0 -1
  672. package/dist/nuxt/runtime/server/api/editor/themes/index.post.d.ts +0 -5
  673. package/dist/nuxt/runtime/server/api/editor/themes/index.post.js +0 -8
  674. package/dist/nuxt/runtime/server/api/editor/themes/index.post.js.map +0 -1
  675. package/dist/nuxt/runtime/server/api/editor/users.get.d.ts +0 -5
  676. package/dist/nuxt/runtime/server/api/editor/users.get.js +0 -8
  677. package/dist/nuxt/runtime/server/api/editor/users.get.js.map +0 -1
  678. package/dist/nuxt/runtime/server/plugins/collab.d.ts +0 -5
  679. package/dist/nuxt/runtime/server/plugins/collab.js +0 -10
  680. package/dist/nuxt/runtime/server/plugins/collab.js.map +0 -1
  681. package/dist/nuxt/runtime/server/routes/collab/[id].d.ts +0 -5
  682. package/dist/nuxt/runtime/server/routes/collab/[id].js +0 -35
  683. package/dist/nuxt/runtime/server/routes/collab/[id].js.map +0 -1
  684. package/dist/nuxt/runtime/server/utils/editor-route.d.ts +0 -11
  685. package/dist/nuxt/runtime/server/utils/editor-route.js.map +0 -1
  686. package/dist/presets/advanced.d.ts +0 -33
  687. package/dist/presets/advanced.js +0 -50
  688. package/dist/presets/advanced.js.map +0 -1
  689. package/dist/presets/simple.d.ts +0 -9
  690. package/dist/presets/simple.js +0 -12
  691. package/dist/presets/simple.js.map +0 -1
  692. package/dist/react/advanced-preset.d.ts +0 -11
  693. package/dist/react/advanced-preset.js +0 -31
  694. package/dist/react/advanced-preset.js.map +0 -1
  695. package/dist/vue/advanced-preset.d.ts +0 -13
  696. package/dist/vue/advanced-preset.js +0 -33
  697. package/dist/vue/advanced-preset.js.map +0 -1
  698. package/docs/extending.md +0 -538
  699. package/docs/integration.md +0 -630
  700. package/docs/llms.md +0 -383
  701. package/docs/usage.md +0 -1076
@@ -22,7 +22,10 @@ const FIELD_TYPES = {
22
22
  textarea: "Langtext",
23
23
  date: "Datum JJJJ-MM-TT",
24
24
  number: "Zahl",
25
- select: "Auswahl"
25
+ select: "Auswahl",
26
+ reference: "Block-ID eines Bausteins",
27
+ bibliography: "Literaturangabe als CSL-JSON-Objekt",
28
+ derivation: "Herkunft, nur lesen"
26
29
  };
27
30
  /** `status (Status: open = Offen, doing = In Arbeit, done = Erledigt)`, `due (Fällig, Datum JJJJ-MM-TT)`. */
28
31
  function fieldText(field) {
@@ -1 +1 @@
1
- {"version":3,"file":"chat.js","names":[],"sources":["../../../../src/features/ai/protocol/chat.ts"],"sourcesContent":["// i18n-ignore-file: model-facing chat system prompt and messages (German prompts stay German whatever the editor's language)\nimport type { ModelMessage } from 'ai'\nimport type { AiBlock, AiContextKind } from '../../../core/feature'\nimport type { StructureMode } from '../../../settings'\nimport { AGENT_TOOL, type AgentOp, type AgentOpFeedback, agentFeedbackText, agentShownMessage } from './agent-ops'\nimport { BLOCK_LINE_COMPOSITE_TEXT, BLOCK_LINE_ECHO_TEXT, BLOCK_LINE_EXAMPLE_ID, BLOCK_LINE_HOST_TEXT, BLOCK_LINE_INTRO, BLOCK_LINE_LIST_TEXT, BLOCK_LINE_MARKERS, BLOCK_LINES_LABEL } from './block-lines'\n\n/**\n * One turn of the document chat; the conversation lives on the client and is sent in full with every message.\n * A user turn carries the decisions on earlier proposals made since the previous turn (`feedback`); an assistant turn\n * the edit operations it proposed (`ops`, possibly without any text) and how many invalid ones were dropped.\n */\nexport type DocumentChatMessage =\n | { role: 'user', content: string, feedback?: AgentOpFeedback[] }\n | { role: 'assistant', content: string, ops?: AgentOp[], dropped?: number }\n\n/** Input limits (characters / messages) of `POST /api/ai/chat`; the client trims to fit before sending. */\nexport const CHAT_LIMITS = { document: 120000, message: 8000, messages: 40 } as const\n\n/** Link target prefix of a quote citation: `[„Zitat“](#block-<id>)`. */\nexport const CITATION_HREF_PREFIX = '#block-'\n\n/**\n * The block ID a citation link points to, or `null` for any other href. Also accepts a bare `#<id>`, which models\n * write now and then despite the instructions; whether the ID exists is up to the caller.\n */\nexport function citationBlockId(href: unknown): string | null {\n if (typeof href !== 'string' || !href.startsWith('#')) return null\n return (href.startsWith(CITATION_HREF_PREFIX) ? href.slice(CITATION_HREF_PREFIX.length) : href.slice(1)) || null\n}\n\n/** A composite kind as the chat model learns it: the client sends the kinds of the editor's `aiContext` with every message. */\nexport type ChatCompositeKind = Pick<AiContextKind, 'id' | 'label' | 'fields' | 'purpose'>\ntype ChatField = ChatCompositeKind['fields'][number]\n\n/** A host-defined block as the chat model learns it: the editor's `aiContext.blocks`, sent with every message. */\nexport type ChatBlock = AiBlock\n\n/**\n * What the model may build and convert into: the editor's composite kinds and host blocks, the `convert` targets it\n * offers, and the user's preferred structure of new content (settings `blocks.structure`).\n */\nexport interface ChatBlockModel { kinds: readonly ChatCompositeKind[], blocks: readonly ChatBlock[], targets: readonly string[], structure: StructureMode }\n\nconst FIELD_TYPES: Record<NonNullable<ChatField['type']>, string> = { text: 'Text', textarea: 'Langtext', date: 'Datum JJJJ-MM-TT', number: 'Zahl', select: 'Auswahl' }\n\n/** `status (Status: open = Offen, doing = In Arbeit, done = Erledigt)`, `due (Fällig, Datum JJJJ-MM-TT)`. */\nfunction fieldText(field: ChatField): string {\n const values = field.options?.length ? `: ${field.options.map(option => `${option.value} = ${option.label}`).join(', ')}` : `, ${FIELD_TYPES[field.type ?? 'text']}`\n return `${field.key} (${field.label}${values})`\n}\n\n/** „Blockmodell“: the document's line format for composites and host blocks holding blocks, the fence the model writes composites in, and `convert`. */\nfunction blockModelText({ kinds, blocks, targets, structure }: ChatBlockModel): string[] {\n const composites = structure === 'composite' && kinds.length > 0\n const example = kinds.find(kind => kind.fields.some(field => field.options?.length)) ?? kinds[0]\n const exampleField = example?.fields.find(field => field.options?.length)\n const exampleMeta = exampleField ? ` {\"${exampleField.key}\":\"${exampleField.options!.at(-1)!.value}\"}` : ''\n return [\n 'Blockmodell:',\n `Blocktypen: Absatz, Überschrift (#, ##, ###), ${BLOCK_LINE_MARKERS}, Codeblock, Redebeitrag („**Name:** Text“) und Bausteine. ${BLOCK_LINE_LIST_TEXT}`,\n ...(blocks.length\n ? [\n `Eigene Blöcke: ${blocks.map(block => `${block.id} (${block.label}): ${block.description} Markdown-Form: „${block.syntax.replace(/\\n/g, '\\\\n')}“. Beispiel: „${block.example.replace(/\\n/g, '\\\\n')}“`).join(' ')}`,\n `${BLOCK_LINE_HOST_TEXT} „update“ auf seine ID mit vollständigem Markdown ersetzt den ganzen Block; „add“ nach einem seiner Inhaltsblöcke fügt innerhalb des Blocks ein, ein Block derselben Art danach.`,\n ]\n : []),\n composites\n ? 'Bevorzugte Gliederung: Bausteine. Neue Inhalte gliederst du mit Bausteinen statt mit Überschriften; Unterabschnitte sind verschachtelte Bausteine (Zaun im Zaun, jeder Zaun endet mit einer eigenen Zeile „:::“). Markdown-Überschriften schreibst du nur als Titelzeile eines Bausteins.'\n : 'Bevorzugte Gliederung: Überschriften. Neue Inhalte gliederst du mit Überschriften (##, ###) statt mit Bausteinen; einen Baustein schreibst du nur, wenn ausdrücklich ein Baustein (Abschnitt, Aufgabe, Notiz …) verlangt wird oder du einen bestehenden Baustein änderst.',\n ...(kinds.length\n ? [\n `Bausteine sind Blöcke mit Titel, Beschreibung, Tags, Feldern und eigenen Inhaltsblöcken. ${BLOCK_LINE_COMPOSITE_TEXT}`,\n `Arten von Bausteinen: ${kinds.map(kind => `${kind.id} (${kind.label}${kind.purpose ? `: ${kind.purpose}` : ''}; ${kind.fields.length ? `Felder: ${kind.fields.map(fieldText).join(', ')}` : 'keine Felder'})`).join('; ')}.`,\n `In „markdown“ schreibst du einen Baustein ohne IDs und ohne Einrückung als Zaun: die Zeile „::: Art {\"feld\":\"wert\"}“ (Felder als JSON, nur gesetzte), dann „## Titel“, „> Beschreibung“ und „Tags: #a #b“ (jeweils nur, wenn vorhanden), dann die Inhaltsblöcke als Markdown, zuletzt die Zeile „:::“. Beispiel: „::: ${example?.id ?? 'note'}${exampleMeta}\\\\n## Angebot prüfen\\\\n- Preise vergleichen\\\\n- Rückmeldung an Anna\\\\n:::“.`,\n '„update“ auf einen Baustein mit Markdown ohne :::-Zaun ersetzt nur seinen Inhalt (Kinder); mit Zaun den ganzen Baustein (Art, Felder, Titel, Beschreibung, Tags und Inhalt).',\n ]\n : []),\n `„convert“ wandelt den Block „id“ in den Blocktyp „to“ um und behält seinen Inhalt. Erlaubte Werte für „to“: ${targets.join(', ')}. Eine Überschrift, die zum Baustein wird, nimmt die folgenden Blöcke bis zur nächsten Überschrift gleicher oder höherer Ebene als Inhalt mit; ein Baustein, der zu einem anderen Blocktyp wird, behält Beschreibung, Tags und Felder als Textzeilen; wird er zur Überschrift, werden seine inneren Bausteine zu Unterüberschriften.`,\n 'Sollen sich Blocktyp und Inhalt oder Felder zugleich ändern (z. B. ein Absatz wird zu einer Aufgabe mit Status), nimm statt „convert“ ein „update“ mit dem vollständigen neuen Markdown samt :::-Zaun; jeder Block bekommt höchstens eine Operation.',\n ]\n}\n\n/** The system prompt: answering with citations, editing through `edit_document`, and the editor's block model. */\nfunction chatSystem(blockModel: ChatBlockModel): string {\n return [\n 'Du beantwortest Fragen zu einem Dokument, meist dem Transkript eines Gesprächs, und bearbeitest es auf Wunsch. Das Dokument steht in der letzten Nachricht der Nutzerin bzw. des Nutzers und ist der aktuelle Stand; frühere Nachrichten bezogen sich womöglich auf einen älteren Stand.',\n BLOCK_LINE_INTRO,\n '',\n 'Fragen:',\n `Belege deine Antworten mit wörtlichen Zitaten: ein zusammenhängender, unveränderter Ausschnitt aus einem einzigen Block. Jedes Zitat ist ein Markdown-Link, dessen Ziel „${CITATION_HREF_PREFIX}“ gefolgt von der vollständigen ID dieses Blocks ist: [„Zitat“](${CITATION_HREF_PREFIX}ID).`,\n `Beispiel zur Zeile oben: Anna kündigt den Start an: [„Wir starten im Mai.“](${CITATION_HREF_PREFIX}${BLOCK_LINE_EXAMPLE_ID})`,\n 'Verwende nur IDs, die im Dokument vorkommen, und nenne IDs nie außerhalb solcher Links.',\n 'Steht die Antwort nicht im Dokument, sag das ehrlich, statt etwas zu erfinden.',\n 'Antworte knapp in Markdown (Absätze, Aufzählungen, **fett**) und in der Sprache der Frage.',\n '',\n 'Änderungen:',\n `Bittet die Nutzerin bzw. der Nutzer darum, das Dokument zu ändern (kürzen, umformulieren, ergänzen, löschen, umwandeln …), rufe das Werkzeug ${AGENT_TOOL} auf, statt den neuen Text im Chat zu schreiben. Schreib davor höchstens ein bis zwei Sätze dazu, was du änderst. Bei Fragen rufst du das Werkzeug nicht auf.`,\n 'Operationen: „update“ ersetzt den Inhalt des Blocks „id“ durch „markdown“; „delete“ löscht den Block „id“; „add“ fügt „markdown“ (ein oder mehrere Blöcke, durch Leerzeilen getrennt) nach dem Block „afterId“ ein („afterId“ gehört bei „add“ immer dazu, für den Dokumentanfang schreibst du ausdrücklich null; mehrere „add“ nach demselben Block werden in der Reihenfolge eingefügt, in der du sie schreibst); „convert“ wandelt den Block „id“ in den Blocktyp „to“ um.',\n `${BLOCK_LINE_ECHO_TEXT} Redebeiträge behalten den fett gesetzten Namen mit Doppelpunkt am Anfang; ein anderer Name wechselt die Sprecherin bzw. den Sprecher. Neue Redebeiträge schreibst du ebenso als „**Name:** Text“.`,\n 'Ändere nur die Blöcke, die die Bitte betrifft; lass unveränderte Blöcke weg. Jeder Block höchstens einmal; eine Operation auf einen Block innerhalb eines Blocks, den eine andere Operation ersetzt oder löscht, ist ungültig (schreibe die Änderung dann in das Markdown der äußeren Operation). Verwende nur IDs aus dem Dokument. Nennt die Nachricht einen Bearbeitungsbereich, beziehen sich alle IDs und afterIds ausschließlich auf Blöcke daraus.',\n 'Jede Änderung wird der Nutzerin bzw. dem Nutzer im Dokument zur Prüfung angezeigt und einzeln übernommen oder abgelehnt. Die Entscheidungen erhältst du mit einer späteren Nachricht („Entscheidungen zu deinen letzten Vorschlägen: …“). Geh auf abgelehnte Vorschläge ein und wiederhole sie nicht unverändert.',\n '',\n ...blockModelText(blockModel),\n ].join('\\n')\n}\n\n/** A user turn as the model reads it: decisions on earlier proposals first, then the message. */\nfunction userText(content: string, feedback: readonly AgentOpFeedback[] | undefined): string {\n const decisions = agentFeedbackText(feedback ?? [])\n return decisions ? `${decisions}\\n\\nNachricht: ${content}` : content\n}\n\n/**\n * Model messages for a chat turn: the history as sent (proposed operations as `edit_document` tool calls), with the\n * current document placed in the last (user) message next to the scope, the latest decisions and the message —\n * document content never goes into the system prompt (the editor's block model does). `scope`: IDs the edits are\n * limited to (null: whole document).\n */\nexport function documentChatMessages(messages: readonly DocumentChatMessage[], document: string, scope: readonly string[] | null, blockModel: ChatBlockModel): ModelMessage[] {\n const history = messages.slice(0, -1).flatMap((message, index): ModelMessage[] => {\n if (message.role === 'user') return [{ role: 'user', content: userText(message.content, message.feedback) }]\n if (!message.ops?.length && !message.dropped) return [{ role: 'assistant', content: message.content }]\n const ops = message.ops ?? []\n const toolCallId = `edit_${index}`\n return [\n {\n role: 'assistant',\n content: [\n ...(message.content ? [{ type: 'text' as const, text: message.content }] : []),\n { type: 'tool-call', toolCallId, toolName: AGENT_TOOL, input: { ops: ops.map(({ op: _op, ...rest }) => rest) } },\n ],\n },\n {\n role: 'tool',\n content: [{ type: 'tool-result', toolCallId, toolName: AGENT_TOOL, output: { type: 'text', value: agentShownMessage(ops, message.dropped ?? 0) } }],\n },\n ]\n })\n const last = messages.at(-1)! as Extract<DocumentChatMessage, { role: 'user' }>\n const range = scope\n ? `Bearbeitungsbereich: die Auswahl der Nutzerin bzw. des Nutzers. Änderungen (id und afterId) nur an diesen Blöcken: ${scope.join(', ')}`\n : 'Bearbeitungsbereich: das ganze Dokument.'\n const decisions = agentFeedbackText(last.feedback ?? [])\n return [\n { role: 'system', content: chatSystem(blockModel) },\n ...history,\n {\n role: 'user',\n content: [\n `${BLOCK_LINES_LABEL}:\\n\"\"\"\\n${document}\\n\"\"\"`,\n range,\n ...(decisions ? [decisions] : []),\n `Nachricht: ${last.content}`,\n ].join('\\n\\n'),\n },\n ]\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"chat.js","names":[],"sources":["../../../../src/features/ai/protocol/chat.ts"],"sourcesContent":["// i18n-ignore-file: model-facing chat system prompt and messages (German prompts stay German whatever the editor's language)\nimport type { ModelMessage } from 'ai'\nimport type { AiBlock, AiContextKind } from '../../../core/feature'\nimport type { StructureMode } from '../../../settings'\nimport { AGENT_TOOL, type AgentOp, type AgentOpFeedback, agentFeedbackText, agentShownMessage } from './agent-ops'\nimport { BLOCK_LINE_COMPOSITE_TEXT, BLOCK_LINE_ECHO_TEXT, BLOCK_LINE_EXAMPLE_ID, BLOCK_LINE_HOST_TEXT, BLOCK_LINE_INTRO, BLOCK_LINE_LIST_TEXT, BLOCK_LINE_MARKERS, BLOCK_LINES_LABEL } from './block-lines'\n\n/**\n * One turn of the document chat; the conversation lives on the client and is sent in full with every message.\n * A user turn carries the decisions on earlier proposals made since the previous turn (`feedback`); an assistant turn\n * the edit operations it proposed (`ops`, possibly without any text) and how many invalid ones were dropped.\n */\nexport type DocumentChatMessage =\n | { role: 'user', content: string, feedback?: AgentOpFeedback[] }\n | { role: 'assistant', content: string, ops?: AgentOp[], dropped?: number }\n\n/** Input limits (characters / messages) of `POST /api/ai/chat`; the client trims to fit before sending. */\nexport const CHAT_LIMITS = { document: 120000, message: 8000, messages: 40 } as const\n\n/** Link target prefix of a quote citation: `[„Zitat“](#block-<id>)`. */\nexport const CITATION_HREF_PREFIX = '#block-'\n\n/**\n * The block ID a citation link points to, or `null` for any other href. Also accepts a bare `#<id>`, which models\n * write now and then despite the instructions; whether the ID exists is up to the caller.\n */\nexport function citationBlockId(href: unknown): string | null {\n if (typeof href !== 'string' || !href.startsWith('#')) return null\n return (href.startsWith(CITATION_HREF_PREFIX) ? href.slice(CITATION_HREF_PREFIX.length) : href.slice(1)) || null\n}\n\n/** A composite kind as the chat model learns it: the client sends the kinds of the editor's `aiContext` with every message. */\nexport type ChatCompositeKind = Pick<AiContextKind, 'id' | 'label' | 'fields' | 'purpose'>\ntype ChatField = ChatCompositeKind['fields'][number]\n\n/** A host-defined block as the chat model learns it: the editor's `aiContext.blocks`, sent with every message. */\nexport type ChatBlock = AiBlock\n\n/**\n * What the model may build and convert into: the editor's composite kinds and host blocks, the `convert` targets it\n * offers, and the user's preferred structure of new content (settings `blocks.structure`).\n */\nexport interface ChatBlockModel { kinds: readonly ChatCompositeKind[], blocks: readonly ChatBlock[], targets: readonly string[], structure: StructureMode }\n\nconst FIELD_TYPES: Record<NonNullable<ChatField['type']>, string> = { text: 'Text', textarea: 'Langtext', date: 'Datum JJJJ-MM-TT', number: 'Zahl', select: 'Auswahl', reference: 'Block-ID eines Bausteins', bibliography: 'Literaturangabe als CSL-JSON-Objekt', derivation: 'Herkunft, nur lesen' }\n\n/** `status (Status: open = Offen, doing = In Arbeit, done = Erledigt)`, `due (Fällig, Datum JJJJ-MM-TT)`. */\nfunction fieldText(field: ChatField): string {\n const values = field.options?.length ? `: ${field.options.map(option => `${option.value} = ${option.label}`).join(', ')}` : `, ${FIELD_TYPES[field.type ?? 'text']}`\n return `${field.key} (${field.label}${values})`\n}\n\n/** „Blockmodell“: the document's line format for composites and host blocks holding blocks, the fence the model writes composites in, and `convert`. */\nfunction blockModelText({ kinds, blocks, targets, structure }: ChatBlockModel): string[] {\n const composites = structure === 'composite' && kinds.length > 0\n const example = kinds.find(kind => kind.fields.some(field => field.options?.length)) ?? kinds[0]\n const exampleField = example?.fields.find(field => field.options?.length)\n const exampleMeta = exampleField ? ` {\"${exampleField.key}\":\"${exampleField.options!.at(-1)!.value}\"}` : ''\n return [\n 'Blockmodell:',\n `Blocktypen: Absatz, Überschrift (#, ##, ###), ${BLOCK_LINE_MARKERS}, Codeblock, Redebeitrag („**Name:** Text“) und Bausteine. ${BLOCK_LINE_LIST_TEXT}`,\n ...(blocks.length\n ? [\n `Eigene Blöcke: ${blocks.map(block => `${block.id} (${block.label}): ${block.description} Markdown-Form: „${block.syntax.replace(/\\n/g, '\\\\n')}“. Beispiel: „${block.example.replace(/\\n/g, '\\\\n')}“`).join(' ')}`,\n `${BLOCK_LINE_HOST_TEXT} „update“ auf seine ID mit vollständigem Markdown ersetzt den ganzen Block; „add“ nach einem seiner Inhaltsblöcke fügt innerhalb des Blocks ein, ein Block derselben Art danach.`,\n ]\n : []),\n composites\n ? 'Bevorzugte Gliederung: Bausteine. Neue Inhalte gliederst du mit Bausteinen statt mit Überschriften; Unterabschnitte sind verschachtelte Bausteine (Zaun im Zaun, jeder Zaun endet mit einer eigenen Zeile „:::“). Markdown-Überschriften schreibst du nur als Titelzeile eines Bausteins.'\n : 'Bevorzugte Gliederung: Überschriften. Neue Inhalte gliederst du mit Überschriften (##, ###) statt mit Bausteinen; einen Baustein schreibst du nur, wenn ausdrücklich ein Baustein (Abschnitt, Aufgabe, Notiz …) verlangt wird oder du einen bestehenden Baustein änderst.',\n ...(kinds.length\n ? [\n `Bausteine sind Blöcke mit Titel, Beschreibung, Tags, Feldern und eigenen Inhaltsblöcken. ${BLOCK_LINE_COMPOSITE_TEXT}`,\n `Arten von Bausteinen: ${kinds.map(kind => `${kind.id} (${kind.label}${kind.purpose ? `: ${kind.purpose}` : ''}; ${kind.fields.length ? `Felder: ${kind.fields.map(fieldText).join(', ')}` : 'keine Felder'})`).join('; ')}.`,\n `In „markdown“ schreibst du einen Baustein ohne IDs und ohne Einrückung als Zaun: die Zeile „::: Art {\"feld\":\"wert\"}“ (Felder als JSON, nur gesetzte), dann „## Titel“, „> Beschreibung“ und „Tags: #a #b“ (jeweils nur, wenn vorhanden), dann die Inhaltsblöcke als Markdown, zuletzt die Zeile „:::“. Beispiel: „::: ${example?.id ?? 'note'}${exampleMeta}\\\\n## Angebot prüfen\\\\n- Preise vergleichen\\\\n- Rückmeldung an Anna\\\\n:::“.`,\n '„update“ auf einen Baustein mit Markdown ohne :::-Zaun ersetzt nur seinen Inhalt (Kinder); mit Zaun den ganzen Baustein (Art, Felder, Titel, Beschreibung, Tags und Inhalt).',\n ]\n : []),\n `„convert“ wandelt den Block „id“ in den Blocktyp „to“ um und behält seinen Inhalt. Erlaubte Werte für „to“: ${targets.join(', ')}. Eine Überschrift, die zum Baustein wird, nimmt die folgenden Blöcke bis zur nächsten Überschrift gleicher oder höherer Ebene als Inhalt mit; ein Baustein, der zu einem anderen Blocktyp wird, behält Beschreibung, Tags und Felder als Textzeilen; wird er zur Überschrift, werden seine inneren Bausteine zu Unterüberschriften.`,\n 'Sollen sich Blocktyp und Inhalt oder Felder zugleich ändern (z. B. ein Absatz wird zu einer Aufgabe mit Status), nimm statt „convert“ ein „update“ mit dem vollständigen neuen Markdown samt :::-Zaun; jeder Block bekommt höchstens eine Operation.',\n ]\n}\n\n/** The system prompt: answering with citations, editing through `edit_document`, and the editor's block model. */\nfunction chatSystem(blockModel: ChatBlockModel): string {\n return [\n 'Du beantwortest Fragen zu einem Dokument, meist dem Transkript eines Gesprächs, und bearbeitest es auf Wunsch. Das Dokument steht in der letzten Nachricht der Nutzerin bzw. des Nutzers und ist der aktuelle Stand; frühere Nachrichten bezogen sich womöglich auf einen älteren Stand.',\n BLOCK_LINE_INTRO,\n '',\n 'Fragen:',\n `Belege deine Antworten mit wörtlichen Zitaten: ein zusammenhängender, unveränderter Ausschnitt aus einem einzigen Block. Jedes Zitat ist ein Markdown-Link, dessen Ziel „${CITATION_HREF_PREFIX}“ gefolgt von der vollständigen ID dieses Blocks ist: [„Zitat“](${CITATION_HREF_PREFIX}ID).`,\n `Beispiel zur Zeile oben: Anna kündigt den Start an: [„Wir starten im Mai.“](${CITATION_HREF_PREFIX}${BLOCK_LINE_EXAMPLE_ID})`,\n 'Verwende nur IDs, die im Dokument vorkommen, und nenne IDs nie außerhalb solcher Links.',\n 'Steht die Antwort nicht im Dokument, sag das ehrlich, statt etwas zu erfinden.',\n 'Antworte knapp in Markdown (Absätze, Aufzählungen, **fett**) und in der Sprache der Frage.',\n '',\n 'Änderungen:',\n `Bittet die Nutzerin bzw. der Nutzer darum, das Dokument zu ändern (kürzen, umformulieren, ergänzen, löschen, umwandeln …), rufe das Werkzeug ${AGENT_TOOL} auf, statt den neuen Text im Chat zu schreiben. Schreib davor höchstens ein bis zwei Sätze dazu, was du änderst. Bei Fragen rufst du das Werkzeug nicht auf.`,\n 'Operationen: „update“ ersetzt den Inhalt des Blocks „id“ durch „markdown“; „delete“ löscht den Block „id“; „add“ fügt „markdown“ (ein oder mehrere Blöcke, durch Leerzeilen getrennt) nach dem Block „afterId“ ein („afterId“ gehört bei „add“ immer dazu, für den Dokumentanfang schreibst du ausdrücklich null; mehrere „add“ nach demselben Block werden in der Reihenfolge eingefügt, in der du sie schreibst); „convert“ wandelt den Block „id“ in den Blocktyp „to“ um.',\n `${BLOCK_LINE_ECHO_TEXT} Redebeiträge behalten den fett gesetzten Namen mit Doppelpunkt am Anfang; ein anderer Name wechselt die Sprecherin bzw. den Sprecher. Neue Redebeiträge schreibst du ebenso als „**Name:** Text“.`,\n 'Ändere nur die Blöcke, die die Bitte betrifft; lass unveränderte Blöcke weg. Jeder Block höchstens einmal; eine Operation auf einen Block innerhalb eines Blocks, den eine andere Operation ersetzt oder löscht, ist ungültig (schreibe die Änderung dann in das Markdown der äußeren Operation). Verwende nur IDs aus dem Dokument. Nennt die Nachricht einen Bearbeitungsbereich, beziehen sich alle IDs und afterIds ausschließlich auf Blöcke daraus.',\n 'Jede Änderung wird der Nutzerin bzw. dem Nutzer im Dokument zur Prüfung angezeigt und einzeln übernommen oder abgelehnt. Die Entscheidungen erhältst du mit einer späteren Nachricht („Entscheidungen zu deinen letzten Vorschlägen: …“). Geh auf abgelehnte Vorschläge ein und wiederhole sie nicht unverändert.',\n '',\n ...blockModelText(blockModel),\n ].join('\\n')\n}\n\n/** A user turn as the model reads it: decisions on earlier proposals first, then the message. */\nfunction userText(content: string, feedback: readonly AgentOpFeedback[] | undefined): string {\n const decisions = agentFeedbackText(feedback ?? [])\n return decisions ? `${decisions}\\n\\nNachricht: ${content}` : content\n}\n\n/**\n * Model messages for a chat turn: the history as sent (proposed operations as `edit_document` tool calls), with the\n * current document placed in the last (user) message next to the scope, the latest decisions and the message —\n * document content never goes into the system prompt (the editor's block model does). `scope`: IDs the edits are\n * limited to (null: whole document).\n */\nexport function documentChatMessages(messages: readonly DocumentChatMessage[], document: string, scope: readonly string[] | null, blockModel: ChatBlockModel): ModelMessage[] {\n const history = messages.slice(0, -1).flatMap((message, index): ModelMessage[] => {\n if (message.role === 'user') return [{ role: 'user', content: userText(message.content, message.feedback) }]\n if (!message.ops?.length && !message.dropped) return [{ role: 'assistant', content: message.content }]\n const ops = message.ops ?? []\n const toolCallId = `edit_${index}`\n return [\n {\n role: 'assistant',\n content: [\n ...(message.content ? [{ type: 'text' as const, text: message.content }] : []),\n { type: 'tool-call', toolCallId, toolName: AGENT_TOOL, input: { ops: ops.map(({ op: _op, ...rest }) => rest) } },\n ],\n },\n {\n role: 'tool',\n content: [{ type: 'tool-result', toolCallId, toolName: AGENT_TOOL, output: { type: 'text', value: agentShownMessage(ops, message.dropped ?? 0) } }],\n },\n ]\n })\n const last = messages.at(-1)! as Extract<DocumentChatMessage, { role: 'user' }>\n const range = scope\n ? `Bearbeitungsbereich: die Auswahl der Nutzerin bzw. des Nutzers. Änderungen (id und afterId) nur an diesen Blöcken: ${scope.join(', ')}`\n : 'Bearbeitungsbereich: das ganze Dokument.'\n const decisions = agentFeedbackText(last.feedback ?? [])\n return [\n { role: 'system', content: chatSystem(blockModel) },\n ...history,\n {\n role: 'user',\n content: [\n `${BLOCK_LINES_LABEL}:\\n\"\"\"\\n${document}\\n\"\"\"`,\n range,\n ...(decisions ? [decisions] : []),\n `Nachricht: ${last.content}`,\n ].join('\\n\\n'),\n },\n ]\n}\n"],"mappings":"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"}
@@ -1,8 +1,9 @@
1
+ import { ModelProfile, ModelRef } from "../../../core/backend-types.js";
1
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 "./block-lines.js";
2
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 "./agent-ops.js";
3
4
  import { CHAT_LIMITS, CITATION_HREF_PREFIX, ChatBlock, ChatBlockModel, ChatCompositeKind, DocumentChatMessage, citationBlockId, documentChatMessages } from "./chat.js";
4
5
  import { AI_COMPLETE_LIMITS, AiCompleteMessage, cleanCompletion, completeMessages, completionReady } from "./complete.js";
5
- import { AI_LANGUAGE_KEYS, MODEL_REF_LIMITS, MODEL_SLOT_KEYS, ModelProfile, ModelRef, UserModelProfile, modelRefSchema } from "./models.js";
6
+ import { AI_LANGUAGE_KEYS, MODEL_REF_LIMITS, MODEL_SLOT_KEYS, UserModelProfile, modelRefSchema } from "./models.js";
6
7
  import { AI_ID_PATTERN, aiBlockInputSchema, aiBlockSchema } from "./schemas.js";
7
8
  import { AI_LIMITS, AI_TASKS, AI_TASK_IDS, AiApplyMode, AiBlockInput, AiInput, AiMessage, AiTask, AiTaskId, blockTasks, inBlockTasks, withHeading, withTaskHeading } from "./tasks.js";
8
- 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_TASKS, AI_TASK_IDS, AgentOp, AgentOpContext, AgentOpFeedback, AgentOpOutcome, AgentOpProblem, AgentOpProblemReason, AgentOpType, AgentTextOptions, AiApplyMode, AiBlockInput, AiCompleteMessage, AiInput, AiMessage, AiTask, AiTaskId, 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, DocumentChatMessage, MODEL_REF_LIMITS, MODEL_SLOT_KEYS, ModelAgentOp, ModelProfile, ModelRef, TRUNCATED_LINE, UserModelProfile, agentFeedbackText, agentOpSummary, agentOpTarget, agentRetryMessage, agentShownMessage, agentUnreadableProblem, aiBlockInputSchema, aiBlockSchema, blockLine, blockTasks, checkAgentOps, citationBlockId, cleanCompletion, completeMessages, completionReady, compositeChromePart, compositeLineClose, compositeLineHeader, continuedLinePrefix, documentChatMessages, inBlockTasks, listLinePrefix, modelRefSchema, nestedLinePrefix, quoteLinePrefix, readBlockLines, singleBlockLine, stripBlockLineEcho, stripListMarkerEcho, withHeading, withTaskHeading };
9
+ 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_TASKS, AI_TASK_IDS, AgentOp, AgentOpContext, AgentOpFeedback, AgentOpOutcome, AgentOpProblem, AgentOpProblemReason, AgentOpType, AgentTextOptions, AiApplyMode, AiBlockInput, AiCompleteMessage, AiInput, AiMessage, AiTask, AiTaskId, 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, DocumentChatMessage, MODEL_REF_LIMITS, MODEL_SLOT_KEYS, ModelAgentOp, type ModelProfile, type ModelRef, TRUNCATED_LINE, UserModelProfile, agentFeedbackText, agentOpSummary, agentOpTarget, agentRetryMessage, agentShownMessage, agentUnreadableProblem, aiBlockInputSchema, aiBlockSchema, blockLine, blockTasks, checkAgentOps, citationBlockId, cleanCompletion, completeMessages, completionReady, compositeChromePart, compositeLineClose, compositeLineHeader, continuedLinePrefix, documentChatMessages, inBlockTasks, listLinePrefix, modelRefSchema, nestedLinePrefix, quoteLinePrefix, readBlockLines, singleBlockLine, stripBlockLineEcho, stripListMarkerEcho, withHeading, withTaskHeading };
@@ -1,6 +1,7 @@
1
1
  import { MessageKey } from "../../../i18n/index.js";
2
2
  import { AiLanguage, ModelSlot } from "../../../settings/values.js";
3
3
  import "../../../settings/index.js";
4
+ import { ModelProfile, ModelRef } from "../../../core/backend-types.js";
4
5
  import { z } from "zod";
5
6
  //#region src/features/ai/protocol/models.d.ts
6
7
  /** Catalog keys of the label and description of each model slot for the settings UI. */
@@ -10,26 +11,10 @@ export declare const MODEL_SLOT_KEYS: Record<ModelSlot, {
10
11
  }>;
11
12
  /** Catalog keys of the display names of the stored target-language ids (`AI_LANGUAGES`); the stored id is what the model is told. */
12
13
  export declare const AI_LANGUAGE_KEYS: Record<AiLanguage, MessageKey>;
13
- /** Profile as the client sees it; presets never expose their key. */
14
- export interface ModelProfile {
15
- id: string;
16
- label: string;
17
- endpoint: string;
18
- model: string;
19
- source: 'preset' | 'user';
20
- }
21
14
  /** Browser-defined profile: its key is sent with each request and never stored on the server. */
22
15
  export interface UserModelProfile extends Omit<ModelProfile, 'source'> {
23
16
  apiKey: string;
24
17
  }
25
- /** Model an AI request runs on: a server preset by id, or an OpenAI-compatible endpoint with its own key. */
26
- export type ModelRef = {
27
- preset: string;
28
- } | {
29
- endpoint: string;
30
- model: string;
31
- apiKey: string;
32
- };
33
18
  /** Maximum lengths (characters) of the fields of a user `ModelRef`. */
34
19
  export declare const MODEL_REF_LIMITS: {
35
20
  readonly endpoint: 500;
@@ -45,4 +30,5 @@ export declare const modelRefSchema: z.ZodUnion<readonly [z.ZodObject<{
45
30
  apiKey: z.ZodString;
46
31
  }, z.core.$strip>]>;
47
32
  //#endregion
33
+ export type { ModelProfile, ModelRef };
48
34
  //# sourceMappingURL=models.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"models.js","names":[],"sources":["../../../../src/features/ai/protocol/models.ts"],"sourcesContent":["import type { MessageKey } from '../../../i18n'\nimport type { AiLanguage, ModelSlot } from '../../../settings'\nimport { z } from 'zod'\n\n/** Catalog keys of the label and description of each model slot for the settings UI. */\nexport const MODEL_SLOT_KEYS: Record<ModelSlot, { labelKey: MessageKey, descriptionKey: MessageKey }> = {\n complete: { labelKey: 'ai.slot.complete.label', descriptionKey: 'ai.slot.complete.description' },\n rewrite: { labelKey: 'ai.slot.rewrite.label', descriptionKey: 'ai.slot.rewrite.description' },\n generate: { labelKey: 'ai.slot.generate.label', descriptionKey: 'ai.slot.generate.description' },\n}\n\n/** Catalog keys of the display names of the stored target-language ids (`AI_LANGUAGES`); the stored id is what the model is told. */\nexport const AI_LANGUAGE_KEYS: Record<AiLanguage, MessageKey> = {\n Deutsch: 'ai.language.de',\n Englisch: 'ai.language.en',\n Französisch: 'ai.language.fr',\n Spanisch: 'ai.language.es',\n Italienisch: 'ai.language.it',\n}\n\n/** Profile as the client sees it; presets never expose their key. */\nexport interface ModelProfile { id: string, label: string, endpoint: string, model: string, source: 'preset' | 'user' }\n\n/** Browser-defined profile: its key is sent with each request and never stored on the server. */\nexport interface UserModelProfile extends Omit<ModelProfile, 'source'> { apiKey: string }\n\n/** Model an AI request runs on: a server preset by id, or an OpenAI-compatible endpoint with its own key. */\nexport type ModelRef = { preset: string } | { endpoint: string, model: string, apiKey: string }\n\n/** Maximum lengths (characters) of the fields of a user `ModelRef`. */\nexport const MODEL_REF_LIMITS = { endpoint: 500, model: 200, apiKey: 500 } as const\n\n/** Validates the `model` field every AI route requires in its body. */\nexport const modelRefSchema = z.union([\n z.object({ preset: z.string().min(1).max(100) }),\n z.object({\n endpoint: z.string().url().max(MODEL_REF_LIMITS.endpoint),\n model: z.string().min(1).max(MODEL_REF_LIMITS.model),\n apiKey: z.string().min(1).max(MODEL_REF_LIMITS.apiKey),\n }),\n])\n"],"mappings":";;;AAKA,MAAa,kBAA2F;CACtG,UAAU;EAAE,UAAU;EAA0B,gBAAgB;CAA+B;CAC/F,SAAS;EAAE,UAAU;EAAyB,gBAAgB;CAA8B;CAC5F,UAAU;EAAE,UAAU;EAA0B,gBAAgB;CAA+B;AACjG;;AAGA,MAAa,mBAAmD;CAC9D,SAAS;CACT,UAAU;CACV,aAAa;CACb,UAAU;CACV,aAAa;AACf;;AAYA,MAAa,mBAAmB;CAAE,UAAU;CAAK,OAAO;CAAK,QAAQ;AAAI;;AAGzE,MAAa,iBAAiB,EAAE,MAAM,CACpC,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,GAC/C,EAAE,OAAO;CACP,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,iBAAiB,QAAQ;CACxD,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,iBAAiB,KAAK;CACnD,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,iBAAiB,MAAM;AACvD,CAAC,CACH,CAAC"}
1
+ {"version":3,"file":"models.js","names":[],"sources":["../../../../src/features/ai/protocol/models.ts"],"sourcesContent":["import type { ModelProfile, ModelRef } from '../../../core/backend-types'\nimport type { MessageKey } from '../../../i18n'\nimport type { AiLanguage, ModelSlot } from '../../../settings'\nimport { z } from 'zod'\n\n/** Catalog keys of the label and description of each model slot for the settings UI. */\nexport const MODEL_SLOT_KEYS: Record<ModelSlot, { labelKey: MessageKey, descriptionKey: MessageKey }> = {\n complete: { labelKey: 'ai.slot.complete.label', descriptionKey: 'ai.slot.complete.description' },\n rewrite: { labelKey: 'ai.slot.rewrite.label', descriptionKey: 'ai.slot.rewrite.description' },\n generate: { labelKey: 'ai.slot.generate.label', descriptionKey: 'ai.slot.generate.description' },\n}\n\n/** Catalog keys of the display names of the stored target-language ids (`AI_LANGUAGES`); the stored id is what the model is told. */\nexport const AI_LANGUAGE_KEYS: Record<AiLanguage, MessageKey> = {\n Deutsch: 'ai.language.de',\n Englisch: 'ai.language.en',\n Französisch: 'ai.language.fr',\n Spanisch: 'ai.language.es',\n Italienisch: 'ai.language.it',\n}\n\n// `ModelProfile` (a profile as the client sees it; presets never expose their key) and `ModelRef` (the model an AI\n// request runs on: a server preset by id, or an OpenAI-compatible endpoint with its own key) are core's, because\n// `EditorBackend.ai` names them; this entry exports them as before.\nexport type { ModelProfile, ModelRef }\n\n/** Browser-defined profile: its key is sent with each request and never stored on the server. */\nexport interface UserModelProfile extends Omit<ModelProfile, 'source'> { apiKey: string }\n\n/** Maximum lengths (characters) of the fields of a user `ModelRef`. */\nexport const MODEL_REF_LIMITS = { endpoint: 500, model: 200, apiKey: 500 } as const\n\n/** Validates the `model` field every AI route requires in its body. */\nexport const modelRefSchema = z.union([\n z.object({ preset: z.string().min(1).max(100) }),\n z.object({\n endpoint: z.string().url().max(MODEL_REF_LIMITS.endpoint),\n model: z.string().min(1).max(MODEL_REF_LIMITS.model),\n apiKey: z.string().min(1).max(MODEL_REF_LIMITS.apiKey),\n }),\n]) satisfies z.ZodType<ModelRef>\n"],"mappings":";;;AAMA,MAAa,kBAA2F;CACtG,UAAU;EAAE,UAAU;EAA0B,gBAAgB;CAA+B;CAC/F,SAAS;EAAE,UAAU;EAAyB,gBAAgB;CAA8B;CAC5F,UAAU;EAAE,UAAU;EAA0B,gBAAgB;CAA+B;AACjG;;AAGA,MAAa,mBAAmD;CAC9D,SAAS;CACT,UAAU;CACV,aAAa;CACb,UAAU;CACV,aAAa;AACf;;AAWA,MAAa,mBAAmB;CAAE,UAAU;CAAK,OAAO;CAAK,QAAQ;AAAI;;AAGzE,MAAa,iBAAiB,EAAE,MAAM,CACpC,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,GAC/C,EAAE,OAAO;CACP,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,iBAAiB,QAAQ;CACxD,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,iBAAiB,KAAK;CACnD,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,iBAAiB,MAAM;AACvD,CAAC,CACH,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { Translate } from "../../i18n/index.js";
2
2
  import { Notifier } from "../../core/notify.js";
3
3
  //#region src/features/ai/rate-limit.d.ts
4
- /** True for an HTTP 429 from an AI endpoint: accepts a status code, a `fetch` Response or a `$fetch` error. */
4
+ /** True for an HTTP 429 from an AI endpoint: accepts a status code, a `BackendError`, a `fetch` Response or a `$fetch` error. */
5
5
  export declare function isRateLimited(source: unknown): boolean;
6
6
  /** Shows the "rate limited" warning notice (`ai.rateLimited`, in the language of `t`); repeated calls refresh one notice instead of stacking. */
7
7
  export declare function notifyAiRateLimited(notify: Notifier, t: Translate): void;
@@ -1,7 +1,9 @@
1
+ import { BackendError } from "../../core/backend.js";
1
2
  //#region src/features/ai/rate-limit.ts
2
- /** True for an HTTP 429 from an AI endpoint: accepts a status code, a `fetch` Response or a `$fetch` error. */
3
+ /** True for an HTTP 429 from an AI endpoint: accepts a status code, a `BackendError`, a `fetch` Response or a `$fetch` error. */
3
4
  function isRateLimited(source) {
4
5
  if (typeof source === "number") return source === 429;
6
+ if (source instanceof BackendError) return source.status === 429;
5
7
  const { status, statusCode } = source ?? {};
6
8
  return status === 429 || statusCode === 429;
7
9
  }
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limit.js","names":[],"sources":["../../../src/features/ai/rate-limit.ts"],"sourcesContent":["import type { Translate } from '../../i18n'\nimport type { Notifier } from '../../core/notify'\n\n/** True for an HTTP 429 from an AI endpoint: accepts a status code, a `fetch` Response or a `$fetch` error. */\nexport function isRateLimited(source: unknown): boolean {\n if (typeof source === 'number') return source === 429\n const { status, statusCode } = (source ?? {}) as { status?: unknown, statusCode?: unknown }\n return status === 429 || statusCode === 429\n}\n\n/** Shows the \"rate limited\" warning notice (`ai.rateLimited`, in the language of `t`); repeated calls refresh one notice instead of stacking. */\nexport function notifyAiRateLimited(notify: Notifier, t: Translate): void {\n notify({ id: 'ai-rate-limited', title: t('ai.rateLimited'), kind: 'warning', icon: 'i-lucide-timer' })\n}\n"],"mappings":";;AAIA,SAAgB,cAAc,QAA0B;CACtD,IAAI,OAAO,WAAW,UAAU,OAAO,WAAW;CAClD,MAAM,EAAE,QAAQ,eAAgB,UAAU,CAAC;CAC3C,OAAO,WAAW,OAAO,eAAe;AAC1C;;AAGA,SAAgB,oBAAoB,QAAkB,GAAoB;CACxE,OAAO;EAAE,IAAI;EAAmB,OAAO,EAAE,gBAAgB;EAAG,MAAM;EAAW,MAAM;CAAiB,CAAC;AACvG"}
1
+ {"version":3,"file":"rate-limit.js","names":[],"sources":["../../../src/features/ai/rate-limit.ts"],"sourcesContent":["import { BackendError } from '../../core/backend'\nimport type { Translate } from '../../i18n'\nimport type { Notifier } from '../../core/notify'\n\n/** True for an HTTP 429 from an AI endpoint: accepts a status code, a `BackendError`, a `fetch` Response or a `$fetch` error. */\nexport function isRateLimited(source: unknown): boolean {\n if (typeof source === 'number') return source === 429\n if (source instanceof BackendError) return source.status === 429\n const { status, statusCode } = (source ?? {}) as { status?: unknown, statusCode?: unknown }\n return status === 429 || statusCode === 429\n}\n\n/** Shows the \"rate limited\" warning notice (`ai.rateLimited`, in the language of `t`); repeated calls refresh one notice instead of stacking. */\nexport function notifyAiRateLimited(notify: Notifier, t: Translate): void {\n notify({ id: 'ai-rate-limited', title: t('ai.rateLimited'), kind: 'warning', icon: 'i-lucide-timer' })\n}\n"],"mappings":";;;AAKA,SAAgB,cAAc,QAA0B;CACtD,IAAI,OAAO,WAAW,UAAU,OAAO,WAAW;CAClD,IAAI,kBAAkB,cAAc,OAAO,OAAO,WAAW;CAC7D,MAAM,EAAE,QAAQ,eAAgB,UAAU,CAAC;CAC3C,OAAO,WAAW,OAAO,eAAe;AAC1C;;AAGA,SAAgB,oBAAoB,QAAkB,GAAoB;CACxE,OAAO;EAAE,IAAI;EAAmB,OAAO,EAAE,gBAAgB;EAAG,MAAM;EAAW,MAAM;CAAiB,CAAC;AACvG"}
@@ -7,14 +7,14 @@ import { Icon } from "../../../react/Icon.js";
7
7
  import { useStore } from "../../../react/use-store.js";
8
8
  import { useEditorSettings } from "../../../react/settings.js";
9
9
  import { Button } from "../../../react/ui/button.js";
10
+ import { InputGroup, InputGroupAddon, InputGroupInput } from "../../../react/ui/input-group.js";
10
11
  import { aiSelectionHighlightKey } from "../ai-selection-highlight.js";
11
- import { AI_SELECTION_MENU_KEY } from "../selection-flow.js";
12
12
  import { Popover, PopoverAnchor, PopoverContent } from "../../../react/ui/popover.js";
13
13
  import { useNotifier } from "../../../react/use-notifier.js";
14
14
  import { Alert, AlertTitle } from "../../../react/ui/alert.js";
15
- import { InputGroup, InputGroupAddon, InputGroupInput } from "../../../react/ui/input-group.js";
16
15
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../../react/ui/select.js";
17
16
  import { previewExtensions } from "../preview-extensions.js";
17
+ import { AI_SELECTION_MENU_KEY } from "../selection-flow.js";
18
18
  import { ModelQuickSwitch } from "./ModelQuickSwitch.js";
19
19
  import { useAiAssistant } from "./use-ai-assistant.js";
20
20
  import { useAiSelectionFlow } from "./use-ai-selection-flow.js";
@@ -6,16 +6,16 @@ import { cn } from "../../../react/ui/utils.js";
6
6
  import { Icon } from "../../../react/Icon.js";
7
7
  import { useStore } from "../../../react/use-store.js";
8
8
  import { Button } from "../../../react/ui/button.js";
9
- import { selectionScope } from "../agent-ops.js";
10
- import { createAiSidebarFlow } from "../sidebar-flow.js";
11
- import { useNotifier } from "../../../react/use-notifier.js";
12
- import { Alert, AlertTitle } from "../../../react/ui/alert.js";
13
9
  import { Input } from "../../../react/ui/input.js";
14
10
  import { Textarea } from "../../../react/ui/textarea.js";
11
+ import { useNotifier } from "../../../react/use-notifier.js";
12
+ import { Alert, AlertTitle } from "../../../react/ui/alert.js";
15
13
  import { ModelQuickSwitch } from "./ModelQuickSwitch.js";
16
14
  import { useAiAssistant } from "./use-ai-assistant.js";
17
15
  import { Badge } from "../../../react/ui/badge.js";
18
16
  import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../../../react/ui/tooltip.js";
17
+ import { selectionScope } from "../agent-ops.js";
18
+ import { createAiSidebarFlow } from "../sidebar-flow.js";
19
19
  import { DocumentChatAnswer } from "./DocumentChatAnswer.js";
20
20
  import { DocumentChatOps } from "./DocumentChatOps.js";
21
21
  import { useDocumentChat } from "./use-document-chat.js";
@@ -1,8 +1,8 @@
1
1
  import { citationBlockId } from "../protocol/chat.js";
2
2
  import { useEditorI18n } from "../../../react/use-editor-i18n.js";
3
- import { documentChatAnswerContent } from "../document-chat.js";
4
3
  import { useNotifier } from "../../../react/use-notifier.js";
5
4
  import { previewExtensions } from "../preview-extensions.js";
5
+ import { documentChatAnswerContent } from "../document-chat.js";
6
6
  import { useEffect, useRef, useState } from "react";
7
7
  import { jsx } from "react/jsx-runtime";
8
8
  import { EditorContent, useEditor } from "@tiptap/react";
@@ -1,7 +1,7 @@
1
1
  import { ConversionProvider } from "../../../core/feature.js";
2
- import "../../../core/index.js";
3
2
  import { AgentOp, AgentOpProblem } from "../protocol/agent-ops.js";
4
3
  import "../protocol/index.js";
4
+ import "../../../core/index.js";
5
5
  import { AgentOpState } from "../agent-op-review.js";
6
6
  //#region src/features/ai/react/DocumentChatOps.d.ts
7
7
  /** The edit operations of one chat answer with their review state; open ones can be decided right here. */
@@ -3,9 +3,9 @@ import { useEditorI18n } from "../../../react/use-editor-i18n.js";
3
3
  import { cn } from "../../../react/ui/utils.js";
4
4
  import { Icon } from "../../../react/Icon.js";
5
5
  import { Button } from "../../../react/ui/button.js";
6
- import { AGENT_OP_OUTCOME_KEYS } from "../agent-ops.js";
7
6
  import { Alert, AlertDescription, AlertTitle } from "../../../react/ui/alert.js";
8
7
  import { Badge } from "../../../react/ui/badge.js";
8
+ import { AGENT_OP_OUTCOME_KEYS } from "../agent-ops.js";
9
9
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
10
  //#region src/features/ai/react/DocumentChatOps.tsx
11
11
  const ICONS = {
@@ -4,10 +4,10 @@ import { useEditorContext } from "../../../react/context.js";
4
4
  import { useEditorI18n } from "../../../react/use-editor-i18n.js";
5
5
  import { Icon } from "../../../react/Icon.js";
6
6
  import { Button } from "../../../react/ui/button.js";
7
- import { isRateLimited } from "../rate-limit.js";
8
- import { Alert, AlertTitle } from "../../../react/ui/alert.js";
9
7
  import { Input } from "../../../react/ui/input.js";
8
+ import { Alert, AlertTitle } from "../../../react/ui/alert.js";
10
9
  import { useModelProfiles } from "./use-model-profiles.js";
10
+ import { isRateLimited } from "../rate-limit.js";
11
11
  import { Label } from "../../../react/ui/label.js";
12
12
  import { Badge } from "../../../react/ui/badge.js";
13
13
  import { useEffect, useMemo, useRef, useState } from "react";
@@ -86,20 +86,18 @@ function SettingsModelProfiles() {
86
86
  removeUserProfile(id);
87
87
  if (draft?.id === id) setDraft(null);
88
88
  }
89
- /** One short completion through the profile's endpoint (`POST /api/ai/complete`). */
89
+ /** One short completion through the profile's endpoint (`ai.complete`). */
90
90
  async function runTest() {
91
91
  if (!draftRef || !draftValid) return;
92
92
  const current = { state: "running" };
93
93
  latestTest.current = current;
94
94
  setTest(current);
95
95
  try {
96
- await app.fetch("/api/ai/complete", {
97
- method: "POST",
98
- body: {
99
- before: "Hallo",
100
- model: draftRef
101
- }
102
- });
96
+ if (!app.backend.ai) throw new Error(t("ai.sse.httpError", { status: 501 }));
97
+ await app.backend.ai.complete({
98
+ before: "Hallo",
99
+ model: draftRef
100
+ }, new AbortController().signal);
103
101
  if (latestTest.current === current) setTest({ state: "ok" });
104
102
  } catch (error) {
105
103
  if (latestTest.current === current) setTest({
@@ -1 +1 @@
1
- {"version":3,"file":"SettingsModelProfiles.js","names":[],"sources":["../../../../src/features/ai/react/SettingsModelProfiles.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from 'react'\nimport { fetchErrorMessage } from '../../../core'\nimport { Icon } from '../../../react/Icon'\nimport { useEditorContext } from '../../../react/context'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport { Alert, AlertTitle } from '../../../react/ui/alert'\nimport { Badge } from '../../../react/ui/badge'\nimport { Button } from '../../../react/ui/button'\nimport { Input } from '../../../react/ui/input'\nimport { Label } from '../../../react/ui/label'\nimport { modelRefSchema, type UserModelProfile } from '../protocol'\nimport { isRateLimited } from '../rate-limit'\nimport { useModelProfiles } from './use-model-profiles'\n\n/** Result of „Testen“; replaced (not mutated) per run, so a stale run recognizes it was superseded. */\ntype TestResult = { state: 'running' } | { state: 'ok' } | { state: 'error', message: string }\n\n/** A labelled form row (the counterpart of Nuxt UI's `UFormField`). */\nfunction Field({ label, description, required, htmlFor, children }: { label: string, description?: string, required?: boolean, htmlFor: string, children: React.ReactNode }) {\n return (\n <div className=\"flex flex-col gap-1.5\">\n <Label htmlFor={htmlFor}>\n {label}\n {required && <span className=\"text-destructive\">*</span>}\n </Label>\n {description && <p className=\"text-xs text-muted-foreground\">{description}</p>}\n {children}\n </div>\n )\n}\n\n/**\n * Section of the „KI“ tab: the server's presets and this browser's own profiles. Profiles are assigned to slots in the\n * section above.\n */\nexport function SettingsModelProfiles() {\n const app = useEditorContext()\n const { t } = useEditorI18n()\n const { presets, userProfiles, saveUserProfile, removeUserProfile } = useModelProfiles()\n\n /** The profile being added or edited; null while the form is closed. */\n const [draft, setDraft] = useState<UserModelProfile | null>(null)\n const [test, setTest] = useState<TestResult | null>(null)\n // The result object of the latest run, so a stale run recognizes it was superseded.\n const latestTest = useRef<TestResult | null>(null)\n\n const draftRef = useMemo(() => draft && { endpoint: draft.endpoint.trim(), model: draft.model.trim(), apiKey: draft.apiKey.trim() }, [draft])\n const draftValid = !!draft?.label.trim() && modelRefSchema.safeParse(draftRef).success\n // A test result belongs to the values it ran with.\n const endpoint = draftRef?.endpoint\n const model = draftRef?.model\n const apiKey = draftRef?.apiKey\n useEffect(() => {\n latestTest.current = null\n setTest(null)\n }, [endpoint, model, apiKey])\n\n function edit(profile?: UserModelProfile) {\n setDraft(profile ? { ...profile } : { id: crypto.randomUUID(), label: '', endpoint: '', model: '', apiKey: '' })\n latestTest.current = null\n setTest(null)\n }\n\n function save() {\n if (!draft || !draftRef || !draftValid) return\n saveUserProfile({ id: draft.id, label: draft.label.trim(), ...draftRef })\n setDraft(null)\n }\n\n function remove(id: string) {\n removeUserProfile(id)\n if (draft?.id === id) setDraft(null)\n }\n\n /** One short completion through the profile's endpoint (`POST /api/ai/complete`). */\n async function runTest() {\n if (!draftRef || !draftValid) return\n const current: TestResult = { state: 'running' }\n latestTest.current = current\n setTest(current)\n try {\n // i18n-ignore: model-facing test prompt sent to the completion endpoint\n await app.fetch('/api/ai/complete', { method: 'POST', body: { before: 'Hallo', model: draftRef } })\n if (latestTest.current === current) setTest({ state: 'ok' })\n }\n catch (error) {\n if (latestTest.current === current) setTest({ state: 'error', message: isRateLimited(error) ? t('ai.rateLimited') : fetchErrorMessage(error) })\n }\n }\n\n const ids = { name: 'ai-profile-label', endpoint: 'ai-profile-endpoint', model: 'ai-profile-model', apiKey: 'ai-profile-key' }\n\n return (\n <div className=\"flex flex-col divide-y divide-border\">\n <div className=\"flex flex-col gap-2 py-3\">\n <p className=\"text-sm font-medium text-foreground\">{t('ai.profiles.server')}</p>\n {!presets.length\n ? <p className=\"text-sm text-muted-foreground\">{t('ai.profiles.noPresets')}</p>\n : (\n <ul className=\"flex flex-col divide-y divide-border rounded-md border border-border\">\n {presets.map(preset => (\n <li key={preset.id} className=\"flex items-center gap-3 px-3 py-2\">\n <Icon name=\"i-lucide-server\" className=\"text-muted-foreground\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium\">{preset.label}</p>\n <p className=\"truncate text-xs text-muted-foreground\">{preset.model} · {preset.endpoint}</p>\n </div>\n <Badge variant=\"secondary\">{t('ai.profiles.serverBadge')}</Badge>\n </li>\n ))}\n </ul>\n )}\n </div>\n\n <div className=\"flex flex-col gap-2 py-3\">\n <div className=\"flex items-center justify-between gap-2\">\n <p className=\"text-sm font-medium text-foreground\">{t('ai.profiles.own')}</p>\n {!draft && (\n <Button size=\"sm\" variant=\"outline\" onClick={() => edit()}>\n <Icon name=\"i-lucide-plus\" />\n {t('ai.profiles.add')}\n </Button>\n )}\n </div>\n {userProfiles.length > 0 && (\n <ul className=\"flex flex-col divide-y divide-border rounded-md border border-border\">\n {userProfiles.map(profile => (\n <li key={profile.id} className=\"flex items-center gap-3 px-3 py-2\">\n <Icon name=\"i-lucide-key-round\" className=\"text-muted-foreground\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium\">{profile.label}</p>\n <p className=\"truncate text-xs text-muted-foreground\">{profile.model} · {profile.endpoint}</p>\n </div>\n <Button size=\"icon-sm\" variant=\"ghost\" aria-label={t('ai.profiles.edit')} onClick={() => edit(profile)}>\n <Icon name=\"i-lucide-pencil\" />\n </Button>\n <Button size=\"icon-sm\" variant=\"ghost\" className=\"text-destructive\" aria-label={t('ai.profiles.delete')} onClick={() => remove(profile.id)}>\n <Icon name=\"i-lucide-trash-2\" />\n </Button>\n </li>\n ))}\n </ul>\n )}\n\n {draft && (\n <form\n className=\"flex flex-col gap-3 rounded-md border border-border p-3\"\n onSubmit={(event) => {\n event.preventDefault()\n save()\n }}\n >\n <Field label={t('ai.profiles.name')} required htmlFor={ids.name}>\n <Input id={ids.name} value={draft.label} placeholder={t('ai.profiles.namePlaceholder')} onChange={event => setDraft({ ...draft, label: event.target.value })} />\n </Field>\n <Field label={t('ai.profiles.endpoint')} description={t('ai.profiles.endpointHelp')} required htmlFor={ids.endpoint}>\n <Input id={ids.endpoint} value={draft.endpoint} placeholder={t('ai.profiles.endpointPlaceholder')} onChange={event => setDraft({ ...draft, endpoint: event.target.value })} />\n </Field>\n <Field label={t('ai.profiles.model')} required htmlFor={ids.model}>\n <Input id={ids.model} value={draft.model} placeholder={t('ai.profiles.modelPlaceholder')} onChange={event => setDraft({ ...draft, model: event.target.value })} />\n </Field>\n <Field label={t('ai.profiles.apiKey')} required htmlFor={ids.apiKey}>\n <Input id={ids.apiKey} type=\"password\" autoComplete=\"off\" value={draft.apiKey} onChange={event => setDraft({ ...draft, apiKey: event.target.value })} />\n </Field>\n {test?.state === 'ok' && (\n <Alert>\n <Icon name=\"i-lucide-check\" />\n <AlertTitle>{t('ai.profiles.testOk')}</AlertTitle>\n </Alert>\n )}\n {test?.state === 'error' && (\n <Alert variant=\"destructive\">\n <Icon name=\"i-lucide-circle-alert\" />\n <AlertTitle>{test.message}</AlertTitle>\n </Alert>\n )}\n <div className=\"flex flex-wrap justify-end gap-2\">\n <Button type=\"button\" variant=\"outline\" disabled={!draftValid || test?.state === 'running'} onClick={() => void runTest()}>\n <Icon name={test?.state === 'running' ? 'i-lucide-loader-circle' : 'i-lucide-plug-zap'} className={test?.state === 'running' ? 'animate-spin' : undefined} />\n {t('ai.profiles.test')}\n </Button>\n <Button type=\"button\" variant=\"ghost\" onClick={() => setDraft(null)}>{t('ai.profiles.cancel')}</Button>\n <Button type=\"submit\" disabled={!draftValid}>{t('ai.profiles.save')}</Button>\n </div>\n </form>\n )}\n </div>\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAkBA,SAAS,MAAM,EAAE,OAAO,aAAa,UAAU,SAAS,YAAqH;CAC3K,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,qBAAC,OAAD;IAAgB;IAAhB,UAAA,CACG,OACA,YAAY,oBAAC,QAAD;KAAM,WAAU;KAAmB,UAAA;IAAO,CAAA,CAClD;;GACN,eAAe,oBAAC,KAAD;IAAG,WAAU;IAAiC,UAAA;GAAe,CAAA;GAC5E;EACE;;AAET;;;;;AAMA,SAAgB,wBAAwB;CACtC,MAAM,MAAM,iBAAiB;CAC7B,MAAM,EAAE,MAAM,cAAc;CAC5B,MAAM,EAAE,SAAS,cAAc,iBAAiB,sBAAsB,iBAAiB;;CAGvF,MAAM,CAAC,OAAO,YAAY,SAAkC,IAAI;CAChE,MAAM,CAAC,MAAM,WAAW,SAA4B,IAAI;CAExD,MAAM,aAAa,OAA0B,IAAI;CAEjD,MAAM,WAAW,cAAc,SAAS;EAAE,UAAU,MAAM,SAAS,KAAK;EAAG,OAAO,MAAM,MAAM,KAAK;EAAG,QAAQ,MAAM,OAAO,KAAK;CAAE,GAAG,CAAC,KAAK,CAAC;CAC5I,MAAM,aAAa,CAAC,CAAC,OAAO,MAAM,KAAK,KAAK,eAAe,UAAU,QAAQ,CAAC,CAAC;CAE/E,MAAM,WAAW,UAAU;CAC3B,MAAM,QAAQ,UAAU;CACxB,MAAM,SAAS,UAAU;CACzB,gBAAgB;EACd,WAAW,UAAU;EACrB,QAAQ,IAAI;CACd,GAAG;EAAC;EAAU;EAAO;CAAM,CAAC;CAE5B,SAAS,KAAK,SAA4B;EACxC,SAAS,UAAU,EAAE,GAAG,QAAQ,IAAI;GAAE,IAAI,OAAO,WAAW;GAAG,OAAO;GAAI,UAAU;GAAI,OAAO;GAAI,QAAQ;EAAG,CAAC;EAC/G,WAAW,UAAU;EACrB,QAAQ,IAAI;CACd;CAEA,SAAS,OAAO;EACd,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,YAAY;EACxC,gBAAgB;GAAE,IAAI,MAAM;GAAI,OAAO,MAAM,MAAM,KAAK;GAAG,GAAG;EAAS,CAAC;EACxE,SAAS,IAAI;CACf;CAEA,SAAS,OAAO,IAAY;EAC1B,kBAAkB,EAAE;EACpB,IAAI,OAAO,OAAO,IAAI,SAAS,IAAI;CACrC;;CAGA,eAAe,UAAU;EACvB,IAAI,CAAC,YAAY,CAAC,YAAY;EAC9B,MAAM,UAAsB,EAAE,OAAO,UAAU;EAC/C,WAAW,UAAU;EACrB,QAAQ,OAAO;EACf,IAAI;GAEF,MAAM,IAAI,MAAM,oBAAoB;IAAE,QAAQ;IAAQ,MAAM;KAAE,QAAQ;KAAS,OAAO;IAAS;GAAE,CAAC;GAClG,IAAI,WAAW,YAAY,SAAS,QAAQ,EAAE,OAAO,KAAK,CAAC;EAC7D,SACO,OAAO;GACZ,IAAI,WAAW,YAAY,SAAS,QAAQ;IAAE,OAAO;IAAS,SAAS,cAAc,KAAK,IAAI,EAAE,gBAAgB,IAAI,kBAAkB,KAAK;GAAE,CAAC;EAChJ;CACF;CAEA,MAAM,MAAM;EAAE,MAAM;EAAoB,UAAU;EAAuB,OAAO;EAAoB,QAAQ;CAAiB;CAE7H,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,oBAAC,KAAD;IAAG,WAAU;IAAuC,UAAA,EAAE,oBAAoB;GAAK,CAAA,GAC9E,CAAC,QAAQ,SACN,oBAAC,KAAD;IAAG,WAAU;IAAiC,UAAA,EAAE,uBAAuB;GAAK,CAAA,IAE1E,oBAAC,MAAD;IAAI,WAAU;IACX,UAAA,QAAQ,KAAI,WACX,qBAAC,MAAD;KAAoB,WAAU;KAA9B,UAAA;MACE,oBAAC,MAAD;OAAM,MAAK;OAAkB,WAAU;MAAyB,CAAA;MAChE,qBAAC,OAAD;OAAK,WAAU;OAAf,UAAA,CACE,oBAAC,KAAD;QAAG,WAAU;QAAgC,UAAA,OAAO;OAAS,CAAA,GAC7D,qBAAC,KAAD;QAAG,WAAU;QAAb,UAAA;SAAuD,OAAO;SAAM;SAAI,OAAO;QAAY;OACxF,CAAA,CAAA;;MACL,oBAAC,OAAD;OAAO,SAAQ;OAAa,UAAA,EAAE,yBAAyB;MAAS,CAAA;KAC9D;IAPK,GAAA,OAAO,EAOZ,CACL;GACC,CAAA,CAEP;EAEL,CAAA,GAAA,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACE,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACE,oBAAC,KAAD;MAAG,WAAU;MAAuC,UAAA,EAAE,iBAAiB;KAAK,CAAA,GAC3E,CAAC,SACA,qBAAC,QAAD;MAAQ,MAAK;MAAK,SAAQ;MAAU,eAAe,KAAK;MAAxD,UAAA,CACE,oBAAC,MAAD,EAAM,MAAK,gBAAiB,CAAA,GAC3B,EAAE,iBAAiB,CACd;KAEP,CAAA,CAAA;;IACJ,aAAa,SAAS,KACrB,oBAAC,MAAD;KAAI,WAAU;KACX,UAAA,aAAa,KAAI,YAChB,qBAAC,MAAD;MAAqB,WAAU;MAA/B,UAAA;OACE,oBAAC,MAAD;QAAM,MAAK;QAAqB,WAAU;OAAyB,CAAA;OACnE,qBAAC,OAAD;QAAK,WAAU;QAAf,UAAA,CACE,oBAAC,KAAD;SAAG,WAAU;SAAgC,UAAA,QAAQ;QAAS,CAAA,GAC9D,qBAAC,KAAD;SAAG,WAAU;SAAb,UAAA;UAAuD,QAAQ;UAAM;UAAI,QAAQ;SAAY;QAC1F,CAAA,CAAA;;OACL,oBAAC,QAAD;QAAQ,MAAK;QAAU,SAAQ;QAAQ,cAAY,EAAE,kBAAkB;QAAG,eAAe,KAAK,OAAO;QACnG,UAAA,oBAAC,MAAD,EAAM,MAAK,kBAAmB,CAAA;OACxB,CAAA;OACR,oBAAC,QAAD;QAAQ,MAAK;QAAU,SAAQ;QAAQ,WAAU;QAAmB,cAAY,EAAE,oBAAoB;QAAG,eAAe,OAAO,QAAQ,EAAE;QACvI,UAAA,oBAAC,MAAD,EAAM,MAAK,mBAAoB,CAAA;OACzB,CAAA;MACN;KAZK,GAAA,QAAQ,EAYb,CACL;IACC,CAAA;IAGL,SACC,qBAAC,QAAD;KACE,WAAU;KACV,WAAW,UAAU;MACnB,MAAM,eAAe;MACrB,KAAK;KACP;KALF,UAAA;MAOE,oBAAC,OAAD;OAAO,OAAO,EAAE,kBAAkB;OAAG,UAAA;OAAS,SAAS,IAAI;OACzD,UAAA,oBAAC,OAAD;QAAO,IAAI,IAAI;QAAM,OAAO,MAAM;QAAO,aAAa,EAAE,6BAA6B;QAAG,WAAU,UAAS,SAAS;SAAE,GAAG;SAAO,OAAO,MAAM,OAAO;QAAM,CAAC;OAAI,CAAA;MAC1J,CAAA;MACP,oBAAC,OAAD;OAAO,OAAO,EAAE,sBAAsB;OAAG,aAAa,EAAE,0BAA0B;OAAG,UAAA;OAAS,SAAS,IAAI;OACzG,UAAA,oBAAC,OAAD;QAAO,IAAI,IAAI;QAAU,OAAO,MAAM;QAAU,aAAa,EAAE,iCAAiC;QAAG,WAAU,UAAS,SAAS;SAAE,GAAG;SAAO,UAAU,MAAM,OAAO;QAAM,CAAC;OAAI,CAAA;MACxK,CAAA;MACP,oBAAC,OAAD;OAAO,OAAO,EAAE,mBAAmB;OAAG,UAAA;OAAS,SAAS,IAAI;OAC1D,UAAA,oBAAC,OAAD;QAAO,IAAI,IAAI;QAAO,OAAO,MAAM;QAAO,aAAa,EAAE,8BAA8B;QAAG,WAAU,UAAS,SAAS;SAAE,GAAG;SAAO,OAAO,MAAM,OAAO;QAAM,CAAC;OAAI,CAAA;MAC5J,CAAA;MACP,oBAAC,OAAD;OAAO,OAAO,EAAE,oBAAoB;OAAG,UAAA;OAAS,SAAS,IAAI;OAC3D,UAAA,oBAAC,OAAD;QAAO,IAAI,IAAI;QAAQ,MAAK;QAAW,cAAa;QAAM,OAAO,MAAM;QAAQ,WAAU,UAAS,SAAS;SAAE,GAAG;SAAO,QAAQ,MAAM,OAAO;QAAM,CAAC;OAAI,CAAA;MAClJ,CAAA;MACN,MAAM,UAAU,QACf,qBAAC,OAAD,EAAA,UAAA,CACE,oBAAC,MAAD,EAAM,MAAK,iBAAkB,CAAA,GAC7B,oBAAC,YAAD,EAAA,UAAa,EAAE,oBAAoB,EAAc,CAAA,CAC5C,EAAA,CAAA;MAER,MAAM,UAAU,WACf,qBAAC,OAAD;OAAO,SAAQ;OAAf,UAAA,CACE,oBAAC,MAAD,EAAM,MAAK,wBAAyB,CAAA,GACpC,oBAAC,YAAD,EAAA,UAAa,KAAK,QAAoB,CAAA,CACjC;;MAET,qBAAC,OAAD;OAAK,WAAU;OAAf,UAAA;QACE,qBAAC,QAAD;SAAQ,MAAK;SAAS,SAAQ;SAAU,UAAU,CAAC,cAAc,MAAM,UAAU;SAAW,eAAe,KAAK,QAAQ;SAAxH,UAAA,CACE,oBAAC,MAAD;UAAM,MAAM,MAAM,UAAU,YAAY,2BAA2B;UAAqB,WAAW,MAAM,UAAU,YAAY,iBAAiB,KAAA;SAAY,CAAA,GAC3J,EAAE,kBAAkB,CACf;;QACR,oBAAC,QAAD;SAAQ,MAAK;SAAS,SAAQ;SAAQ,eAAe,SAAS,IAAI;SAAI,UAAA,EAAE,oBAAoB;QAAU,CAAA;QACtG,oBAAC,QAAD;SAAQ,MAAK;SAAS,UAAU,CAAC;SAAa,UAAA,EAAE,kBAAkB;QAAU,CAAA;OACzE;;KACD;;GAEL;EACF,CAAA,CAAA;;AAET"}
1
+ {"version":3,"file":"SettingsModelProfiles.js","names":[],"sources":["../../../../src/features/ai/react/SettingsModelProfiles.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from 'react'\nimport { fetchErrorMessage } from '../../../core'\nimport { Icon } from '../../../react/Icon'\nimport { useEditorContext } from '../../../react/context'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport { Alert, AlertTitle } from '../../../react/ui/alert'\nimport { Badge } from '../../../react/ui/badge'\nimport { Button } from '../../../react/ui/button'\nimport { Input } from '../../../react/ui/input'\nimport { Label } from '../../../react/ui/label'\nimport { modelRefSchema, type UserModelProfile } from '../protocol'\nimport { isRateLimited } from '../rate-limit'\nimport { useModelProfiles } from './use-model-profiles'\n\n/** Result of „Testen“; replaced (not mutated) per run, so a stale run recognizes it was superseded. */\ntype TestResult = { state: 'running' } | { state: 'ok' } | { state: 'error', message: string }\n\n/** A labelled form row (the counterpart of Nuxt UI's `UFormField`). */\nfunction Field({ label, description, required, htmlFor, children }: { label: string, description?: string, required?: boolean, htmlFor: string, children: React.ReactNode }) {\n return (\n <div className=\"flex flex-col gap-1.5\">\n <Label htmlFor={htmlFor}>\n {label}\n {required && <span className=\"text-destructive\">*</span>}\n </Label>\n {description && <p className=\"text-xs text-muted-foreground\">{description}</p>}\n {children}\n </div>\n )\n}\n\n/**\n * Section of the „KI“ tab: the server's presets and this browser's own profiles. Profiles are assigned to slots in the\n * section above.\n */\nexport function SettingsModelProfiles() {\n const app = useEditorContext()\n const { t } = useEditorI18n()\n const { presets, userProfiles, saveUserProfile, removeUserProfile } = useModelProfiles()\n\n /** The profile being added or edited; null while the form is closed. */\n const [draft, setDraft] = useState<UserModelProfile | null>(null)\n const [test, setTest] = useState<TestResult | null>(null)\n // The result object of the latest run, so a stale run recognizes it was superseded.\n const latestTest = useRef<TestResult | null>(null)\n\n const draftRef = useMemo(() => draft && { endpoint: draft.endpoint.trim(), model: draft.model.trim(), apiKey: draft.apiKey.trim() }, [draft])\n const draftValid = !!draft?.label.trim() && modelRefSchema.safeParse(draftRef).success\n // A test result belongs to the values it ran with.\n const endpoint = draftRef?.endpoint\n const model = draftRef?.model\n const apiKey = draftRef?.apiKey\n useEffect(() => {\n latestTest.current = null\n setTest(null)\n }, [endpoint, model, apiKey])\n\n function edit(profile?: UserModelProfile) {\n setDraft(profile ? { ...profile } : { id: crypto.randomUUID(), label: '', endpoint: '', model: '', apiKey: '' })\n latestTest.current = null\n setTest(null)\n }\n\n function save() {\n if (!draft || !draftRef || !draftValid) return\n saveUserProfile({ id: draft.id, label: draft.label.trim(), ...draftRef })\n setDraft(null)\n }\n\n function remove(id: string) {\n removeUserProfile(id)\n if (draft?.id === id) setDraft(null)\n }\n\n /** One short completion through the profile's endpoint (`ai.complete`). */\n async function runTest() {\n if (!draftRef || !draftValid) return\n const current: TestResult = { state: 'running' }\n latestTest.current = current\n setTest(current)\n try {\n if (!app.backend.ai) throw new Error(t('ai.sse.httpError', { status: 501 }))\n // i18n-ignore: model-facing test prompt sent to the completion endpoint\n await app.backend.ai.complete({ before: 'Hallo', model: draftRef }, new AbortController().signal)\n if (latestTest.current === current) setTest({ state: 'ok' })\n }\n catch (error) {\n if (latestTest.current === current) setTest({ state: 'error', message: isRateLimited(error) ? t('ai.rateLimited') : fetchErrorMessage(error) })\n }\n }\n\n const ids = { name: 'ai-profile-label', endpoint: 'ai-profile-endpoint', model: 'ai-profile-model', apiKey: 'ai-profile-key' }\n\n return (\n <div className=\"flex flex-col divide-y divide-border\">\n <div className=\"flex flex-col gap-2 py-3\">\n <p className=\"text-sm font-medium text-foreground\">{t('ai.profiles.server')}</p>\n {!presets.length\n ? <p className=\"text-sm text-muted-foreground\">{t('ai.profiles.noPresets')}</p>\n : (\n <ul className=\"flex flex-col divide-y divide-border rounded-md border border-border\">\n {presets.map(preset => (\n <li key={preset.id} className=\"flex items-center gap-3 px-3 py-2\">\n <Icon name=\"i-lucide-server\" className=\"text-muted-foreground\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium\">{preset.label}</p>\n <p className=\"truncate text-xs text-muted-foreground\">{preset.model} · {preset.endpoint}</p>\n </div>\n <Badge variant=\"secondary\">{t('ai.profiles.serverBadge')}</Badge>\n </li>\n ))}\n </ul>\n )}\n </div>\n\n <div className=\"flex flex-col gap-2 py-3\">\n <div className=\"flex items-center justify-between gap-2\">\n <p className=\"text-sm font-medium text-foreground\">{t('ai.profiles.own')}</p>\n {!draft && (\n <Button size=\"sm\" variant=\"outline\" onClick={() => edit()}>\n <Icon name=\"i-lucide-plus\" />\n {t('ai.profiles.add')}\n </Button>\n )}\n </div>\n {userProfiles.length > 0 && (\n <ul className=\"flex flex-col divide-y divide-border rounded-md border border-border\">\n {userProfiles.map(profile => (\n <li key={profile.id} className=\"flex items-center gap-3 px-3 py-2\">\n <Icon name=\"i-lucide-key-round\" className=\"text-muted-foreground\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium\">{profile.label}</p>\n <p className=\"truncate text-xs text-muted-foreground\">{profile.model} · {profile.endpoint}</p>\n </div>\n <Button size=\"icon-sm\" variant=\"ghost\" aria-label={t('ai.profiles.edit')} onClick={() => edit(profile)}>\n <Icon name=\"i-lucide-pencil\" />\n </Button>\n <Button size=\"icon-sm\" variant=\"ghost\" className=\"text-destructive\" aria-label={t('ai.profiles.delete')} onClick={() => remove(profile.id)}>\n <Icon name=\"i-lucide-trash-2\" />\n </Button>\n </li>\n ))}\n </ul>\n )}\n\n {draft && (\n <form\n className=\"flex flex-col gap-3 rounded-md border border-border p-3\"\n onSubmit={(event) => {\n event.preventDefault()\n save()\n }}\n >\n <Field label={t('ai.profiles.name')} required htmlFor={ids.name}>\n <Input id={ids.name} value={draft.label} placeholder={t('ai.profiles.namePlaceholder')} onChange={event => setDraft({ ...draft, label: event.target.value })} />\n </Field>\n <Field label={t('ai.profiles.endpoint')} description={t('ai.profiles.endpointHelp')} required htmlFor={ids.endpoint}>\n <Input id={ids.endpoint} value={draft.endpoint} placeholder={t('ai.profiles.endpointPlaceholder')} onChange={event => setDraft({ ...draft, endpoint: event.target.value })} />\n </Field>\n <Field label={t('ai.profiles.model')} required htmlFor={ids.model}>\n <Input id={ids.model} value={draft.model} placeholder={t('ai.profiles.modelPlaceholder')} onChange={event => setDraft({ ...draft, model: event.target.value })} />\n </Field>\n <Field label={t('ai.profiles.apiKey')} required htmlFor={ids.apiKey}>\n <Input id={ids.apiKey} type=\"password\" autoComplete=\"off\" value={draft.apiKey} onChange={event => setDraft({ ...draft, apiKey: event.target.value })} />\n </Field>\n {test?.state === 'ok' && (\n <Alert>\n <Icon name=\"i-lucide-check\" />\n <AlertTitle>{t('ai.profiles.testOk')}</AlertTitle>\n </Alert>\n )}\n {test?.state === 'error' && (\n <Alert variant=\"destructive\">\n <Icon name=\"i-lucide-circle-alert\" />\n <AlertTitle>{test.message}</AlertTitle>\n </Alert>\n )}\n <div className=\"flex flex-wrap justify-end gap-2\">\n <Button type=\"button\" variant=\"outline\" disabled={!draftValid || test?.state === 'running'} onClick={() => void runTest()}>\n <Icon name={test?.state === 'running' ? 'i-lucide-loader-circle' : 'i-lucide-plug-zap'} className={test?.state === 'running' ? 'animate-spin' : undefined} />\n {t('ai.profiles.test')}\n </Button>\n <Button type=\"button\" variant=\"ghost\" onClick={() => setDraft(null)}>{t('ai.profiles.cancel')}</Button>\n <Button type=\"submit\" disabled={!draftValid}>{t('ai.profiles.save')}</Button>\n </div>\n </form>\n )}\n </div>\n </div>\n )\n}\n"],"mappings":"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"}
@@ -3,7 +3,7 @@ import "../index.js";
3
3
  import { Editor } from "@tiptap/core";
4
4
  //#region src/features/ai/react/use-ai-assistant.d.ts
5
5
  /**
6
- * Streams `/api/ai/generate` into component state, on the task's model slot (see `createAiAssistant`). A running
6
+ * Streams the backend's `generate` into component state, on the task's model slot (see `createAiAssistant`). A running
7
7
  * request is aborted when the component unmounts. The 429 notice goes to `editor`'s surface (else the app's notifier).
8
8
  */
9
9
  export declare function useAiAssistant(editor?: Editor): {
@@ -1,19 +1,19 @@
1
1
  import { useEditorContext } from "../../../react/context.js";
2
2
  import { useStore } from "../../../react/use-store.js";
3
- import { createAiAssistant } from "../assistant.js";
4
3
  import { modelProfiles } from "../model-profiles.js";
5
4
  import { useNotifier } from "../../../react/use-notifier.js";
5
+ import { createAiAssistant } from "../assistant.js";
6
6
  import { useEffect, useMemo } from "react";
7
7
  //#region src/features/ai/react/use-ai-assistant.ts
8
8
  /**
9
- * Streams `/api/ai/generate` into component state, on the task's model slot (see `createAiAssistant`). A running
9
+ * Streams the backend's `generate` into component state, on the task's model slot (see `createAiAssistant`). A running
10
10
  * request is aborted when the component unmounts. The 429 notice goes to `editor`'s surface (else the app's notifier).
11
11
  */
12
12
  function useAiAssistant(editor) {
13
13
  const app = useEditorContext();
14
14
  const notify = useNotifier(editor);
15
15
  const assistant = useMemo(() => createAiAssistant({
16
- fetch: app.fetch,
16
+ ai: app.backend.ai,
17
17
  modelRef: modelProfiles(app).modelRef,
18
18
  notify,
19
19
  t: app.t
@@ -1 +1 @@
1
- {"version":3,"file":"use-ai-assistant.js","names":[],"sources":["../../../../src/features/ai/react/use-ai-assistant.ts"],"sourcesContent":["import { useEffect, useMemo } from 'react'\nimport { useEditorContext } from '../../../react/context'\nimport { useStore } from '../../../react/use-store'\nimport { type AiRunBody, type AiStatus, createAiAssistant } from '../assistant'\nimport { modelProfiles } from '../model-profiles'\nimport { useNotifier } from '../../../react/use-notifier'\nimport type { Editor } from '@tiptap/core'\n\nexport type { AiRunBody, AiStatus }\n\n/**\n * Streams `/api/ai/generate` into component state, on the task's model slot (see `createAiAssistant`). A running\n * request is aborted when the component unmounts. The 429 notice goes to `editor`'s surface (else the app's notifier).\n */\nexport function useAiAssistant(editor?: Editor) {\n const app = useEditorContext()\n const notify = useNotifier(editor)\n const assistant = useMemo(\n () => createAiAssistant({ fetch: app.fetch, modelRef: modelProfiles(app).modelRef, notify, t: app.t }),\n [app, notify],\n )\n useEffect(() => () => assistant.abort(), [assistant])\n const state = useStore(assistant.state)\n /** `getState` reads the current state after an await (a render's `state` would be stale). */\n return { model: assistant, ...state, getState: assistant.state.get, run: assistant.run, abort: assistant.abort, reset: assistant.reset, clearError: assistant.clearError }\n}\n"],"mappings":";;;;;;;;;;;AAcA,SAAgB,eAAe,QAAiB;CAC9C,MAAM,MAAM,iBAAiB;CAC7B,MAAM,SAAS,YAAY,MAAM;CACjC,MAAM,YAAY,cACV,kBAAkB;EAAE,OAAO,IAAI;EAAO,UAAU,cAAc,GAAG,CAAC,CAAC;EAAU;EAAQ,GAAG,IAAI;CAAE,CAAC,GACrG,CAAC,KAAK,MAAM,CACd;CACA,sBAAsB,UAAU,MAAM,GAAG,CAAC,SAAS,CAAC;;CAGpD,OAAO;EAAE,OAAO;EAAW,GAFb,SAAS,UAAU,KAEC;EAAG,UAAU,UAAU,MAAM;EAAK,KAAK,UAAU;EAAK,OAAO,UAAU;EAAO,OAAO,UAAU;EAAO,YAAY,UAAU;CAAW;AAC3K"}
1
+ {"version":3,"file":"use-ai-assistant.js","names":[],"sources":["../../../../src/features/ai/react/use-ai-assistant.ts"],"sourcesContent":["import { useEffect, useMemo } from 'react'\nimport { useEditorContext } from '../../../react/context'\nimport { useStore } from '../../../react/use-store'\nimport { type AiRunBody, type AiStatus, createAiAssistant } from '../assistant'\nimport { modelProfiles } from '../model-profiles'\nimport { useNotifier } from '../../../react/use-notifier'\nimport type { Editor } from '@tiptap/core'\n\nexport type { AiRunBody, AiStatus }\n\n/**\n * Streams the backend's `generate` into component state, on the task's model slot (see `createAiAssistant`). A running\n * request is aborted when the component unmounts. The 429 notice goes to `editor`'s surface (else the app's notifier).\n */\nexport function useAiAssistant(editor?: Editor) {\n const app = useEditorContext()\n const notify = useNotifier(editor)\n const assistant = useMemo(\n () => createAiAssistant({ ai: app.backend.ai, modelRef: modelProfiles(app).modelRef, notify, t: app.t }),\n [app, notify],\n )\n useEffect(() => () => assistant.abort(), [assistant])\n const state = useStore(assistant.state)\n /** `getState` reads the current state after an await (a render's `state` would be stale). */\n return { model: assistant, ...state, getState: assistant.state.get, run: assistant.run, abort: assistant.abort, reset: assistant.reset, clearError: assistant.clearError }\n}\n"],"mappings":";;;;;;;;;;;AAcA,SAAgB,eAAe,QAAiB;CAC9C,MAAM,MAAM,iBAAiB;CAC7B,MAAM,SAAS,YAAY,MAAM;CACjC,MAAM,YAAY,cACV,kBAAkB;EAAE,IAAI,IAAI,QAAQ;EAAI,UAAU,cAAc,GAAG,CAAC,CAAC;EAAU;EAAQ,GAAG,IAAI;CAAE,CAAC,GACvG,CAAC,KAAK,MAAM,CACd;CACA,sBAAsB,UAAU,MAAM,GAAG,CAAC,SAAS,CAAC;;CAGpD,OAAO;EAAE,OAAO;EAAW,GAFb,SAAS,UAAU,KAEC;EAAG,UAAU,UAAU,MAAM;EAAK,KAAK,UAAU;EAAK,OAAO,UAAU;EAAO,OAAO,UAAU;EAAO,YAAY,UAAU;CAAW;AAC3K"}
@@ -1,8 +1,8 @@
1
1
  import { useEditorContext } from "../../../react/context.js";
2
2
  import { useStore } from "../../../react/use-store.js";
3
- import { createDocumentChat } from "../document-chat-model.js";
4
3
  import { modelProfiles } from "../model-profiles.js";
5
4
  import { useNotifier } from "../../../react/use-notifier.js";
5
+ import { createDocumentChat } from "../document-chat-model.js";
6
6
  import { useEffect, useMemo } from "react";
7
7
  //#region src/features/ai/react/use-document-chat.ts
8
8
  /**
@@ -14,7 +14,7 @@ function useDocumentChat(editor) {
14
14
  const app = useEditorContext();
15
15
  const notify = useNotifier(editor);
16
16
  const chat = useMemo(() => createDocumentChat({
17
- fetch: app.fetch,
17
+ ai: app.backend.ai,
18
18
  modelRef: modelProfiles(app).modelRef,
19
19
  notify,
20
20
  t: app.t
@@ -1 +1 @@
1
- {"version":3,"file":"use-document-chat.js","names":[],"sources":["../../../../src/features/ai/react/use-document-chat.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { useEffect, useMemo } from 'react'\nimport { useEditorContext } from '../../../react/context'\nimport { useStore } from '../../../react/use-store'\nimport { createDocumentChat } from '../document-chat-model'\nimport { modelProfiles } from '../model-profiles'\nimport { useNotifier } from '../../../react/use-notifier'\n\n/**\n * Document chat state for a component (see `createDocumentChat`): re-renders as the conversation streams in. A running\n * answer is aborted when the component unmounts; hosts that want the conversation to survive closing keep the\n * component mounted (hidden). The 429 notice goes to `editor`'s surface (else the app's notifier).\n */\nexport function useDocumentChat(editor?: Editor) {\n const app = useEditorContext()\n const notify = useNotifier(editor)\n const chat = useMemo(\n () => createDocumentChat({ fetch: app.fetch, modelRef: modelProfiles(app).modelRef, notify, t: app.t }),\n [app, notify],\n )\n useEffect(() => () => chat.abort(), [chat])\n const state = useStore(chat.state)\n /** `getState` reads the current state after an await (a render's `state` would be stale). */\n return {\n /** The underlying model, for flows that act on it (`createAiSidebarFlow`). */\n model: chat,\n ...state,\n getState: chat.state.get,\n ask: chat.ask,\n abort: chat.abort,\n reset: chat.reset,\n decide: chat.decide,\n reveal: chat.reveal,\n addGeneration: chat.addGeneration,\n updateGeneration: chat.updateGeneration,\n removeGeneration: chat.removeGeneration,\n clearError: chat.clearError,\n }\n}\n"],"mappings":";;;;;;;;;;;;AAaA,SAAgB,gBAAgB,QAAiB;CAC/C,MAAM,MAAM,iBAAiB;CAC7B,MAAM,SAAS,YAAY,MAAM;CACjC,MAAM,OAAO,cACL,mBAAmB;EAAE,OAAO,IAAI;EAAO,UAAU,cAAc,GAAG,CAAC,CAAC;EAAU;EAAQ,GAAG,IAAI;CAAE,CAAC,GACtG,CAAC,KAAK,MAAM,CACd;CACA,sBAAsB,KAAK,MAAM,GAAG,CAAC,IAAI,CAAC;;CAG1C,OAAO;;EAEL,OAAO;EACP,GALY,SAAS,KAAK,KAKnB;EACP,UAAU,KAAK,MAAM;EACrB,KAAK,KAAK;EACV,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,QAAQ,KAAK;EACb,QAAQ,KAAK;EACb,eAAe,KAAK;EACpB,kBAAkB,KAAK;EACvB,kBAAkB,KAAK;EACvB,YAAY,KAAK;CACnB;AACF"}
1
+ {"version":3,"file":"use-document-chat.js","names":[],"sources":["../../../../src/features/ai/react/use-document-chat.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { useEffect, useMemo } from 'react'\nimport { useEditorContext } from '../../../react/context'\nimport { useStore } from '../../../react/use-store'\nimport { createDocumentChat } from '../document-chat-model'\nimport { modelProfiles } from '../model-profiles'\nimport { useNotifier } from '../../../react/use-notifier'\n\n/**\n * Document chat state for a component (see `createDocumentChat`): re-renders as the conversation streams in. A running\n * answer is aborted when the component unmounts; hosts that want the conversation to survive closing keep the\n * component mounted (hidden). The 429 notice goes to `editor`'s surface (else the app's notifier).\n */\nexport function useDocumentChat(editor?: Editor) {\n const app = useEditorContext()\n const notify = useNotifier(editor)\n const chat = useMemo(\n () => createDocumentChat({ ai: app.backend.ai, modelRef: modelProfiles(app).modelRef, notify, t: app.t }),\n [app, notify],\n )\n useEffect(() => () => chat.abort(), [chat])\n const state = useStore(chat.state)\n /** `getState` reads the current state after an await (a render's `state` would be stale). */\n return {\n /** The underlying model, for flows that act on it (`createAiSidebarFlow`). */\n model: chat,\n ...state,\n getState: chat.state.get,\n ask: chat.ask,\n abort: chat.abort,\n reset: chat.reset,\n decide: chat.decide,\n reveal: chat.reveal,\n addGeneration: chat.addGeneration,\n updateGeneration: chat.updateGeneration,\n removeGeneration: chat.removeGeneration,\n clearError: chat.clearError,\n }\n}\n"],"mappings":";;;;;;;;;;;;AAaA,SAAgB,gBAAgB,QAAiB;CAC/C,MAAM,MAAM,iBAAiB;CAC7B,MAAM,SAAS,YAAY,MAAM;CACjC,MAAM,OAAO,cACL,mBAAmB;EAAE,IAAI,IAAI,QAAQ;EAAI,UAAU,cAAc,GAAG,CAAC,CAAC;EAAU;EAAQ,GAAG,IAAI;CAAE,CAAC,GACxG,CAAC,KAAK,MAAM,CACd;CACA,sBAAsB,KAAK,MAAM,GAAG,CAAC,IAAI,CAAC;;CAG1C,OAAO;;EAEL,OAAO;EACP,GALY,SAAS,KAAK,KAKnB;EACP,UAAU,KAAK,MAAM;EACrB,KAAK,KAAK;EACV,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,QAAQ,KAAK;EACb,QAAQ,KAAK;EACb,eAAe,KAAK;EACpB,kBAAkB,KAAK;EACvB,kBAAkB,KAAK;EACvB,YAAY,KAAK;CACnB;AACF"}
@@ -1,6 +1,7 @@
1
1
  import { ModelSlot } from "../../../settings/values.js";
2
2
  import "../../../settings/index.js";
3
- import { ModelProfile, ModelRef, UserModelProfile } from "../protocol/models.js";
3
+ import { ModelProfile, ModelRef } from "../../../core/backend-types.js";
4
+ import { UserModelProfile } from "../protocol/models.js";
4
5
  import "../protocol/index.js";
5
6
  //#region src/features/ai/react/use-model-profiles.d.ts
6
7
  /**
@@ -1,8 +1,8 @@
1
+ import { ReadonlyStore } from "../../core/store.js";
1
2
  import { Translate } from "../../i18n/index.js";
2
3
  import { AiLanguage } from "../../settings/values.js";
3
4
  import "../../settings/index.js";
4
5
  import { Notifier } from "../../core/notify.js";
5
- import { ReadonlyStore } from "../../core/store.js";
6
6
  import { AiTask } from "./protocol/tasks.js";
7
7
  import "./protocol/index.js";
8
8
  import { AiResultAction } from "./ai-apply.js";
@@ -6,8 +6,8 @@ import { captureRange, releaseRanges, resolveRange } from "../../core/doc-anchor
6
6
  import { selectionRange } from "../../core/selection-range.js";
7
7
  import { AI_LIMITS, AI_TASKS } from "./protocol/tasks.js";
8
8
  import { aiApplyFailure, applyAiResult, documentMarkdown, insertAtCaretLine, rangeMarkdown } from "./ai-apply.js";
9
- import { aiMenuActionsOf } from "./ai-menu.js";
10
9
  import { hideAiSelectionHighlight, showAiSelectionHighlight } from "./ai-selection-highlight.js";
10
+ import { aiMenuActionsOf } from "./ai-menu.js";
11
11
  import { TextSelection } from "@tiptap/pm/state";
12
12
  //#region src/features/ai/selection-flow.ts
13
13
  /** Plugin key of the bubble menu that offers the AI menu; the flow hides that bubble when it opens on the selection. */
@@ -1,6 +1,6 @@
1
+ import { ReadonlyStore } from "../../core/store.js";
1
2
  import { Translate } from "../../i18n/index.js";
2
3
  import { Notifier } from "../../core/notify.js";
3
- import { ReadonlyStore } from "../../core/store.js";
4
4
  import { AiTask } from "./protocol/tasks.js";
5
5
  import "./protocol/index.js";
6
6
  import { AgentScope } from "./agent-ops.js";
@@ -2,8 +2,8 @@ import { aiContextOf } from "../../core/pipeline.js";
2
2
  import { createStore } from "../../core/store.js";
3
3
  import { releaseRanges } from "../../core/doc-anchors.js";
4
4
  import { AI_LIMITS, withTaskHeading } from "./protocol/tasks.js";
5
- import { selectionScope } from "./agent-ops.js";
6
5
  import { aiApplyFailure, applyAiResult, captureTarget, documentMarkdown, formatTaskResult, insertBlocksAtTarget } from "./ai-apply.js";
6
+ import { selectionScope } from "./agent-ops.js";
7
7
  //#region src/features/ai/sidebar-flow.ts
8
8
  /**
9
9
  * The AI sidebar's flow over a document chat and an assistant, shared by both UI surfaces: they only render the
@@ -3,7 +3,7 @@ import { Editor } from "@tiptap/core";
3
3
  import { MaybeRefOrGetter } from "vue";
4
4
  //#region src/features/ai/use-ai-assistant.d.ts
5
5
  /**
6
- * Streams `/api/ai/generate` into Vue refs on the task's model slot: a thin hook over `createAiAssistant`. Call it
6
+ * Streams the backend's `generate` into Vue refs on the task's model slot: a thin hook over `createAiAssistant`. Call it
7
7
  * during component setup (it injects the editor context); the request stops with the component's scope. The 429 notice
8
8
  * goes to `editor`'s surface (else the app's notifier).
9
9
  */
@@ -1,19 +1,19 @@
1
1
  import { useEditorContext } from "../../vue/context.js";
2
- import { createAiAssistant } from "./assistant.js";
3
2
  import { modelProfiles } from "./model-profiles.js";
3
+ import { createAiAssistant } from "./assistant.js";
4
4
  import { useNotifier } from "../../vue/use-notifier.js";
5
5
  import { useStoreRef } from "../../vue/store-ref.js";
6
6
  import { computed, getCurrentScope, onScopeDispose } from "vue";
7
7
  //#region src/features/ai/use-ai-assistant.ts
8
8
  /**
9
- * Streams `/api/ai/generate` into Vue refs on the task's model slot: a thin hook over `createAiAssistant`. Call it
9
+ * Streams the backend's `generate` into Vue refs on the task's model slot: a thin hook over `createAiAssistant`. Call it
10
10
  * during component setup (it injects the editor context); the request stops with the component's scope. The 429 notice
11
11
  * goes to `editor`'s surface (else the app's notifier).
12
12
  */
13
13
  function useAiAssistant(editor) {
14
14
  const context = useEditorContext();
15
15
  const assistant = createAiAssistant({
16
- fetch: context.fetch,
16
+ ai: context.backend.ai,
17
17
  modelRef: modelProfiles(context).modelRef,
18
18
  notify: useNotifier(editor),
19
19
  t: context.t
@@ -1 +1 @@
1
- {"version":3,"file":"use-ai-assistant.js","names":[],"sources":["../../../src/features/ai/use-ai-assistant.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { computed, getCurrentScope, type MaybeRefOrGetter, onScopeDispose } from 'vue'\nimport { useEditorContext } from '../../vue/context'\nimport { useStoreRef } from '../../vue/store-ref'\nimport { useNotifier } from '../../vue/use-notifier'\nimport { createAiAssistant } from './assistant'\nimport { modelProfiles } from './model-profiles'\n\nexport type { AiRunBody, AiStatus } from './assistant'\n\n/**\n * Streams `/api/ai/generate` into Vue refs on the task's model slot: a thin hook over `createAiAssistant`. Call it\n * during component setup (it injects the editor context); the request stops with the component's scope. The 429 notice\n * goes to `editor`'s surface (else the app's notifier).\n */\nexport function useAiAssistant(editor?: MaybeRefOrGetter<Editor | undefined>) {\n const context = useEditorContext()\n const assistant = createAiAssistant({ fetch: context.fetch, modelRef: modelProfiles(context).modelRef, notify: useNotifier(editor), t: context.t })\n const snapshot = useStoreRef(assistant.state)\n if (getCurrentScope()) onScopeDispose(assistant.abort)\n const { run, abort, reset, clearError } = assistant\n return {\n /** The underlying model, for flows that act on it (`createAiSidebarFlow`). */\n model: assistant,\n status: computed(() => snapshot.value.status),\n output: computed(() => snapshot.value.output),\n error: computed(() => snapshot.value.error),\n run,\n abort,\n reset,\n clearError,\n }\n}\n"],"mappings":";;;;;;;;;;;;AAeA,SAAgB,eAAe,QAA+C;CAC5E,MAAM,UAAU,iBAAiB;CACjC,MAAM,YAAY,kBAAkB;EAAE,OAAO,QAAQ;EAAO,UAAU,cAAc,OAAO,CAAC,CAAC;EAAU,QAAQ,YAAY,MAAM;EAAG,GAAG,QAAQ;CAAE,CAAC;CAClJ,MAAM,WAAW,YAAY,UAAU,KAAK;CAC5C,IAAI,gBAAgB,GAAG,eAAe,UAAU,KAAK;CACrD,MAAM,EAAE,KAAK,OAAO,OAAO,eAAe;CAC1C,OAAO;;EAEL,OAAO;EACP,QAAQ,eAAe,SAAS,MAAM,MAAM;EAC5C,QAAQ,eAAe,SAAS,MAAM,MAAM;EAC5C,OAAO,eAAe,SAAS,MAAM,KAAK;EAC1C;EACA;EACA;EACA;CACF;AACF"}
1
+ {"version":3,"file":"use-ai-assistant.js","names":[],"sources":["../../../src/features/ai/use-ai-assistant.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { computed, getCurrentScope, type MaybeRefOrGetter, onScopeDispose } from 'vue'\nimport { useEditorContext } from '../../vue/context'\nimport { useStoreRef } from '../../vue/store-ref'\nimport { useNotifier } from '../../vue/use-notifier'\nimport { createAiAssistant } from './assistant'\nimport { modelProfiles } from './model-profiles'\n\nexport type { AiRunBody, AiStatus } from './assistant'\n\n/**\n * Streams the backend's `generate` into Vue refs on the task's model slot: a thin hook over `createAiAssistant`. Call it\n * during component setup (it injects the editor context); the request stops with the component's scope. The 429 notice\n * goes to `editor`'s surface (else the app's notifier).\n */\nexport function useAiAssistant(editor?: MaybeRefOrGetter<Editor | undefined>) {\n const context = useEditorContext()\n const assistant = createAiAssistant({ ai: context.backend.ai, modelRef: modelProfiles(context).modelRef, notify: useNotifier(editor), t: context.t })\n const snapshot = useStoreRef(assistant.state)\n if (getCurrentScope()) onScopeDispose(assistant.abort)\n const { run, abort, reset, clearError } = assistant\n return {\n /** The underlying model, for flows that act on it (`createAiSidebarFlow`). */\n model: assistant,\n status: computed(() => snapshot.value.status),\n output: computed(() => snapshot.value.output),\n error: computed(() => snapshot.value.error),\n run,\n abort,\n reset,\n clearError,\n }\n}\n"],"mappings":";;;;;;;;;;;;AAeA,SAAgB,eAAe,QAA+C;CAC5E,MAAM,UAAU,iBAAiB;CACjC,MAAM,YAAY,kBAAkB;EAAE,IAAI,QAAQ,QAAQ;EAAI,UAAU,cAAc,OAAO,CAAC,CAAC;EAAU,QAAQ,YAAY,MAAM;EAAG,GAAG,QAAQ;CAAE,CAAC;CACpJ,MAAM,WAAW,YAAY,UAAU,KAAK;CAC5C,IAAI,gBAAgB,GAAG,eAAe,UAAU,KAAK;CACrD,MAAM,EAAE,KAAK,OAAO,OAAO,eAAe;CAC1C,OAAO;;EAEL,OAAO;EACP,QAAQ,eAAe,SAAS,MAAM,MAAM;EAC5C,QAAQ,eAAe,SAAS,MAAM,MAAM;EAC5C,OAAO,eAAe,SAAS,MAAM,KAAK;EAC1C;EACA;EACA;EACA;CACF;AACF"}