@ecsplico/editor 3.5.1 → 4.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.
- package/CHANGELOG.md +71 -0
- package/dist/adapters/direct-ai.d.ts +4 -4
- package/dist/adapters/direct-ai.js +2 -2
- package/dist/adapters/direct-ai.js.map +1 -1
- package/dist/adapters/document-state.d.ts +1 -1
- package/dist/adapters/document-state.js.map +1 -1
- package/dist/adapters/forge.d.ts +2 -2
- package/dist/adapters/forge.js.map +1 -1
- package/dist/adapters/nitro.d.ts +11 -3
- package/dist/adapters/nitro.js +3 -1
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +6 -6
- package/dist/adapters/shared.js.map +1 -1
- package/dist/code/CodeSurface.vue.d.ts +3 -3
- package/dist/config/index.d.ts +14 -14
- package/dist/config/index.js +8 -8
- package/dist/config/index.js.map +1 -1
- package/dist/core/backend-types.d.ts +3 -3
- package/dist/core/backend-types.js.map +1 -1
- package/dist/core/backend.d.ts +4 -4
- package/dist/core/backend.js.map +1 -1
- package/dist/core/block-convert.d.ts +1 -1
- package/dist/core/block-convert.js +5 -5
- package/dist/core/block-convert.js.map +1 -1
- package/dist/core/block-transfer.d.ts +8 -4
- package/dist/core/block-transfer.js +23 -14
- package/dist/core/block-transfer.js.map +1 -1
- package/dist/core/capabilities.d.ts +113 -0
- package/dist/core/capabilities.js +155 -0
- package/dist/core/capabilities.js.map +1 -0
- package/dist/core/command-types.d.ts +1 -1
- package/dist/core/context.js.map +1 -1
- package/dist/core/convert.d.ts +5 -5
- package/dist/core/convert.js +5 -5
- package/dist/core/convert.js.map +1 -1
- package/dist/core/core-feature.js +1 -1
- package/dist/core/define-editor.d.ts +2 -2
- package/dist/core/define-editor.js +34 -6
- package/dist/core/define-editor.js.map +1 -1
- package/dist/core/derivation.d.ts +119 -0
- package/dist/core/derivation.js +187 -0
- package/dist/core/derivation.js.map +1 -0
- package/dist/core/derive.d.ts +61 -0
- package/dist/core/derive.js +69 -0
- package/dist/core/derive.js.map +1 -0
- package/dist/core/extension-points.d.ts +16 -0
- package/dist/core/feature-context.d.ts +5 -1
- package/dist/core/feature-context.js +10 -3
- package/dist/core/feature-context.js.map +1 -1
- package/dist/core/feature.d.ts +41 -19
- package/dist/core/feature.js.map +1 -1
- package/dist/core/fences.js +1 -1
- package/dist/core/fences.js.map +1 -1
- package/dist/core/index.d.ts +6 -2
- package/dist/core/index.js +5 -1
- package/dist/core/pipeline.d.ts +14 -5
- package/dist/core/pipeline.js +19 -7
- package/dist/core/pipeline.js.map +1 -1
- package/dist/core/properties.d.ts +22 -0
- package/dist/core/properties.js +17 -0
- package/dist/core/properties.js.map +1 -0
- package/dist/core/schema/block-ids.js +5 -5
- package/dist/core/schema/block-ids.js.map +1 -1
- package/dist/core/schema/index.d.ts +2 -1
- package/dist/core/schema/index.js +2 -1
- package/dist/core/schema/index.js.map +1 -1
- package/dist/core/schema/opaque-fence.d.ts +4 -4
- package/dist/core/schema/opaque-fence.js +7 -7
- package/dist/core/schema/opaque-fence.js.map +1 -1
- package/dist/core/schema/persisted-names.d.ts +58 -0
- package/dist/core/schema/persisted-names.js +96 -0
- package/dist/core/schema/persisted-names.js.map +1 -0
- package/dist/core/toolbar-items.js +1 -1
- package/dist/core/toolbar-items.js.map +1 -1
- package/dist/core/util.js +5 -1
- package/dist/core/util.js.map +1 -1
- package/dist/document/DocumentSurface.vue.d.ts +3 -3
- package/dist/features/ai/agent-ops.js +1 -1
- package/dist/features/ai/ai-review.js +1 -1
- package/dist/features/ai/assistant.d.ts +4 -4
- package/dist/features/ai/assistant.js +1 -1
- package/dist/features/ai/assistant.js.map +1 -1
- package/dist/features/ai/components/AiSelectionMenu.js +1 -1
- package/dist/features/ai/components/AiSelectionMenu.js.map +1 -1
- package/dist/features/ai/components/ModelQuickSwitch.js +7 -7
- package/dist/features/ai/components/ModelQuickSwitch.js.map +1 -1
- package/dist/features/ai/components/ModelQuickSwitch.vue.d.ts +4 -4
- package/dist/features/ai/components/SettingsAiTab.js +8 -8
- package/dist/features/ai/components/SettingsAiTab.js.map +1 -1
- package/dist/features/ai/components/SettingsModelProfiles.js +1 -1
- package/dist/features/ai/components/SettingsModelProfiles.js.map +1 -1
- package/dist/features/ai/document-chat-model.d.ts +2 -2
- package/dist/features/ai/document-chat-model.js +5 -5
- package/dist/features/ai/document-chat-model.js.map +1 -1
- package/dist/features/ai/document-chat.js +2 -2
- package/dist/features/ai/document-chat.js.map +1 -1
- package/dist/features/ai/feature.d.ts +2 -2
- package/dist/features/ai/feature.js +2 -2
- package/dist/features/ai/feature.js.map +1 -1
- package/dist/features/ai/ghost-autocomplete.d.ts +4 -4
- package/dist/features/ai/ghost-autocomplete.js +1 -1
- package/dist/features/ai/ghost-autocomplete.js.map +1 -1
- package/dist/features/ai/index.d.ts +3 -3
- package/dist/features/ai/index.js +2 -2
- package/dist/features/ai/model-profiles.d.ts +9 -9
- package/dist/features/ai/model-profiles.js +13 -13
- package/dist/features/ai/model-profiles.js.map +1 -1
- package/dist/features/ai/protocol/agent-ops.d.ts +2 -2
- package/dist/features/ai/protocol/agent-ops.js +1 -1
- package/dist/features/ai/protocol/agent-ops.js.map +1 -1
- package/dist/features/ai/protocol/block-lines.d.ts +7 -7
- package/dist/features/ai/protocol/block-lines.js +10 -10
- package/dist/features/ai/protocol/block-lines.js.map +1 -1
- package/dist/features/ai/protocol/chat.d.ts +5 -5
- package/dist/features/ai/protocol/chat.js +12 -12
- package/dist/features/ai/protocol/chat.js.map +1 -1
- package/dist/features/ai/protocol/generate.d.ts +1 -1
- package/dist/features/ai/protocol/generate.js +1 -1
- package/dist/features/ai/protocol/generate.js.map +1 -1
- package/dist/features/ai/protocol/index.d.ts +3 -3
- package/dist/features/ai/protocol/index.js +2 -2
- package/dist/features/ai/protocol/models.d.ts +3 -3
- package/dist/features/ai/protocol/models.js +3 -3
- package/dist/features/ai/protocol/models.js.map +1 -1
- package/dist/features/ai/protocol/schemas.d.ts +1 -1
- package/dist/features/ai/protocol/schemas.js +1 -1
- package/dist/features/ai/protocol/schemas.js.map +1 -1
- package/dist/features/ai/protocol/tasks.d.ts +5 -5
- package/dist/features/ai/protocol/tasks.js +12 -12
- package/dist/features/ai/protocol/tasks.js.map +1 -1
- package/dist/features/ai/react/AiSelectionMenu.js.map +1 -1
- package/dist/features/ai/react/ModelQuickSwitch.d.ts +4 -4
- package/dist/features/ai/react/ModelQuickSwitch.js +6 -6
- package/dist/features/ai/react/ModelQuickSwitch.js.map +1 -1
- package/dist/features/ai/react/SettingsAiTab.d.ts +1 -1
- package/dist/features/ai/react/SettingsAiTab.js +8 -8
- package/dist/features/ai/react/SettingsAiTab.js.map +1 -1
- package/dist/features/ai/react/SettingsModelProfiles.d.ts +1 -1
- package/dist/features/ai/react/SettingsModelProfiles.js +1 -1
- package/dist/features/ai/react/SettingsModelProfiles.js.map +1 -1
- package/dist/features/ai/react/use-ai-assistant.d.ts +1 -1
- package/dist/features/ai/react/use-ai-assistant.js +1 -1
- package/dist/features/ai/react/use-ai-assistant.js.map +1 -1
- package/dist/features/ai/react/use-model-profiles.d.ts +5 -5
- package/dist/features/ai/react/use-model-profiles.js +2 -2
- package/dist/features/ai/react/use-model-profiles.js.map +1 -1
- package/dist/features/ai/use-ai-assistant.d.ts +1 -1
- package/dist/features/ai/use-ai-assistant.js +1 -1
- package/dist/features/ai/use-ai-assistant.js.map +1 -1
- package/dist/features/ai/use-model-profiles.d.ts +4 -4
- package/dist/features/ai/use-model-profiles.js +2 -2
- package/dist/features/ai/use-model-profiles.js.map +1 -1
- package/dist/features/block-ui/block-actions.d.ts +8 -4
- package/dist/features/block-ui/block-actions.js +38 -22
- package/dist/features/block-ui/block-actions.js.map +1 -1
- package/dist/features/block-ui/block-target.d.ts +29 -0
- package/dist/features/block-ui/block-target.js +63 -0
- package/dist/features/block-ui/block-target.js.map +1 -0
- package/dist/features/block-ui/components/BlockHandles.js +3 -3
- package/dist/features/block-ui/components/BlockHandles.js.map +1 -1
- package/dist/features/block-ui/components/BlockUi.js +11 -23
- package/dist/features/block-ui/components/BlockUi.js.map +1 -1
- package/dist/features/block-ui/feature.d.ts +3 -2
- package/dist/features/block-ui/feature.js +3 -2
- package/dist/features/block-ui/feature.js.map +1 -1
- package/dist/features/block-ui/handle-geometry.js +12 -23
- package/dist/features/block-ui/handle-geometry.js.map +1 -1
- package/dist/features/block-ui/index.d.ts +2 -1
- package/dist/features/block-ui/index.js +2 -1
- package/dist/features/block-ui/react/BlockHandles.d.ts +1 -1
- package/dist/features/block-ui/react/BlockHandles.js +4 -4
- package/dist/features/block-ui/react/BlockHandles.js.map +1 -1
- package/dist/features/block-ui/react/BlockUi.js +13 -25
- package/dist/features/block-ui/react/BlockUi.js.map +1 -1
- package/dist/features/comments/model.js +1 -1
- package/dist/features/composites/accepted-children.d.ts +5 -4
- package/dist/features/composites/accepted-children.js +26 -26
- package/dist/features/composites/accepted-children.js.map +1 -1
- package/dist/features/composites/ai-brief.d.ts +4 -4
- package/dist/features/composites/ai-brief.js +14 -12
- package/dist/features/composites/ai-brief.js.map +1 -1
- package/dist/features/composites/anchors.d.ts +1 -1
- package/dist/features/composites/anchors.js.map +1 -1
- package/dist/features/composites/baskets.d.ts +1 -1
- package/dist/features/composites/baskets.js.map +1 -1
- package/dist/features/composites/bibliography-command.d.ts +1 -1
- package/dist/features/composites/bibliography-form.js +1 -1
- package/dist/features/composites/bibliography-form.js.map +1 -1
- package/dist/features/composites/bibliography.js.map +1 -1
- package/dist/features/composites/block-types-json.d.ts +38 -0
- package/dist/features/composites/block-types-json.js +122 -0
- package/dist/features/composites/block-types-json.js.map +1 -0
- package/dist/features/composites/block-types.d.ts +119 -0
- package/dist/features/composites/block-types.js +343 -0
- package/dist/features/composites/block-types.js.map +1 -0
- package/dist/features/composites/capabilities.js +109 -0
- package/dist/features/composites/capabilities.js.map +1 -0
- package/dist/features/composites/components/BibliographyEditor.js +5 -5
- package/dist/features/composites/components/BibliographyEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeBasketMenu.js +2 -2
- package/dist/features/composites/components/CompositeBasketMenu.js.map +1 -1
- package/dist/features/composites/components/CompositeChrome.js +18 -8
- package/dist/features/composites/components/CompositeChrome.js.map +1 -1
- package/dist/features/composites/components/CompositeChrome.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeDetails.js +11 -10
- package/dist/features/composites/components/CompositeDetails.js.map +1 -1
- package/dist/features/composites/components/CompositeDetails.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeFieldEditor.js +7 -7
- package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeFieldEditor.vue.d.ts +5 -5
- package/dist/features/composites/components/CompositeInspector.js +136 -113
- package/dist/features/composites/components/CompositeInspector.js.map +1 -1
- package/dist/features/composites/components/CompositeInspector.vue.d.ts +3 -3
- package/dist/features/composites/components/CompositeStatusMenu.js +2 -2
- package/dist/features/composites/components/CompositeStatusMenu.js.map +1 -1
- package/dist/features/composites/components/CompositeSummaryEditor.js +1 -1
- package/dist/features/composites/components/CompositeSummaryEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeSummaryEditor.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeTable.js +2 -2
- package/dist/features/composites/components/CompositeTable.js.map +1 -1
- package/dist/features/composites/components/CompositeTagsEditor.js +1 -1
- package/dist/features/composites/components/CompositeTagsEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeTagsEditor.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeView.js +19 -17
- package/dist/features/composites/components/CompositeView.js.map +1 -1
- package/dist/features/composites/components/DerivationBadge.js +15 -6
- package/dist/features/composites/components/DerivationBadge.js.map +1 -1
- package/dist/features/composites/components/FocusChip.js +1 -1
- package/dist/features/composites/components/FocusChip.js.map +1 -1
- package/dist/features/composites/components/FocusChip.vue.d.ts +1 -1
- package/dist/features/composites/components/ReferenceFieldSelect.js +3 -3
- package/dist/features/composites/components/ReferenceFieldSelect.js.map +1 -1
- package/dist/features/composites/components/ReferenceView.js +1 -1
- package/dist/features/composites/components/ReferenceView.js.map +1 -1
- package/dist/features/composites/components/SettingsEditingTab.js +18 -18
- package/dist/features/composites/components/SettingsEditingTab.js.map +1 -1
- package/dist/features/composites/components/SettingsEditingTab.vue.d.ts +3 -3
- package/dist/features/composites/convert.d.ts +4 -4
- package/dist/features/composites/convert.js +27 -28
- package/dist/features/composites/convert.js.map +1 -1
- package/dist/features/composites/derived-chrome.js +34 -28
- package/dist/features/composites/derived-chrome.js.map +1 -1
- package/dist/features/composites/editing-settings-keys.js +6 -6
- package/dist/features/composites/editing-settings-keys.js.map +1 -1
- package/dist/features/composites/feature.d.ts +10 -10
- package/dist/features/composites/feature.js +58 -46
- package/dist/features/composites/feature.js.map +1 -1
- package/dist/features/composites/fences.d.ts +3 -3
- package/dist/features/composites/fences.js +18 -13
- package/dist/features/composites/fences.js.map +1 -1
- package/dist/features/composites/focus.d.ts +10 -10
- package/dist/features/composites/focus.js +11 -11
- package/dist/features/composites/focus.js.map +1 -1
- package/dist/features/composites/heading-composites.d.ts +5 -5
- package/dist/features/composites/heading-composites.js +13 -16
- package/dist/features/composites/heading-composites.js.map +1 -1
- package/dist/features/composites/index.d.ts +20 -18
- package/dist/features/composites/index.js +9 -7
- package/dist/features/composites/inspector-model.d.ts +45 -22
- package/dist/features/composites/inspector-model.js +53 -14
- package/dist/features/composites/inspector-model.js.map +1 -1
- package/dist/features/composites/legacy.d.ts +5 -4
- package/dist/features/composites/legacy.js +16 -23
- package/dist/features/composites/legacy.js.map +1 -1
- package/dist/features/composites/markdown-export.js +3 -3
- package/dist/features/composites/markdown-export.js.map +1 -1
- package/dist/features/composites/merge.d.ts +8 -7
- package/dist/features/composites/merge.js +39 -12
- package/dist/features/composites/merge.js.map +1 -1
- package/dist/features/composites/meta-display.js +5 -5
- package/dist/features/composites/meta-display.js.map +1 -1
- package/dist/features/composites/meta-keys.d.ts +5 -5
- package/dist/features/composites/meta-keys.js +8 -8
- package/dist/features/composites/meta-keys.js.map +1 -1
- package/dist/features/composites/node-views.d.ts +3 -3
- package/dist/features/composites/node-views.js +2 -2
- package/dist/features/composites/node-views.js.map +1 -1
- package/dist/features/composites/nodes.d.ts +13 -13
- package/dist/features/composites/nodes.js +100 -77
- package/dist/features/composites/nodes.js.map +1 -1
- package/dist/features/composites/outline.d.ts +15 -12
- package/dist/features/composites/outline.js +24 -21
- package/dist/features/composites/outline.js.map +1 -1
- package/dist/features/composites/properties.d.ts +51 -0
- package/dist/features/composites/properties.js +89 -0
- package/dist/features/composites/properties.js.map +1 -0
- package/dist/features/composites/react/BibliographyEditor.js +5 -5
- package/dist/features/composites/react/BibliographyEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeBasketMenu.js +2 -2
- package/dist/features/composites/react/CompositeBasketMenu.js.map +1 -1
- package/dist/features/composites/react/CompositeChrome.d.ts +1 -1
- package/dist/features/composites/react/CompositeChrome.js +15 -6
- package/dist/features/composites/react/CompositeChrome.js.map +1 -1
- package/dist/features/composites/react/CompositeDetails.d.ts +1 -1
- package/dist/features/composites/react/CompositeDetails.js +11 -10
- package/dist/features/composites/react/CompositeDetails.js.map +1 -1
- package/dist/features/composites/react/CompositeFieldEditor.d.ts +5 -5
- package/dist/features/composites/react/CompositeFieldEditor.js +6 -6
- package/dist/features/composites/react/CompositeFieldEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeInspector.d.ts +3 -3
- package/dist/features/composites/react/CompositeInspector.js +142 -128
- package/dist/features/composites/react/CompositeInspector.js.map +1 -1
- package/dist/features/composites/react/CompositeStatusMenu.js +2 -2
- package/dist/features/composites/react/CompositeStatusMenu.js.map +1 -1
- package/dist/features/composites/react/CompositeSummaryEditor.d.ts +1 -1
- package/dist/features/composites/react/CompositeSummaryEditor.js +1 -1
- package/dist/features/composites/react/CompositeSummaryEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeTable.d.ts +1 -1
- package/dist/features/composites/react/CompositeTable.js +3 -3
- package/dist/features/composites/react/CompositeTable.js.map +1 -1
- package/dist/features/composites/react/CompositeTagsEditor.d.ts +1 -1
- package/dist/features/composites/react/CompositeTagsEditor.js +1 -1
- package/dist/features/composites/react/CompositeTagsEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeView.js +17 -15
- package/dist/features/composites/react/CompositeView.js.map +1 -1
- package/dist/features/composites/react/DerivationBadge.js +13 -4
- package/dist/features/composites/react/DerivationBadge.js.map +1 -1
- package/dist/features/composites/react/FocusChip.d.ts +1 -1
- package/dist/features/composites/react/FocusChip.js +1 -1
- package/dist/features/composites/react/FocusChip.js.map +1 -1
- package/dist/features/composites/react/ReferenceFieldSelect.js +3 -3
- package/dist/features/composites/react/ReferenceFieldSelect.js.map +1 -1
- package/dist/features/composites/react/ReferenceView.d.ts +1 -1
- package/dist/features/composites/react/ReferenceView.js +1 -1
- package/dist/features/composites/react/ReferenceView.js.map +1 -1
- package/dist/features/composites/react/SettingsEditingTab.d.ts +4 -4
- package/dist/features/composites/react/SettingsEditingTab.js +20 -20
- package/dist/features/composites/react/SettingsEditingTab.js.map +1 -1
- package/dist/features/composites/react.js +1 -1
- package/dist/features/composites/react.js.map +1 -1
- package/dist/features/composites/reference-ai.js +1 -1
- package/dist/features/composites/reference-ai.js.map +1 -1
- package/dist/features/composites/reference-label.d.ts +3 -3
- package/dist/features/composites/reference-label.js +6 -6
- package/dist/features/composites/reference-label.js.map +1 -1
- package/dist/features/composites/reference-suggestion.d.ts +1 -1
- package/dist/features/composites/reference-suggestion.js +3 -3
- package/dist/features/composites/reference-suggestion.js.map +1 -1
- package/dist/features/composites/reference-text.d.ts +2 -2
- package/dist/features/composites/reference-text.js +4 -4
- package/dist/features/composites/reference-text.js.map +1 -1
- package/dist/features/composites/reference.d.ts +3 -3
- package/dist/features/composites/reference.js +1 -1
- package/dist/features/composites/reference.js.map +1 -1
- package/dist/features/composites/reveal-source.d.ts +3 -3
- package/dist/features/composites/reveal-source.js +6 -6
- package/dist/features/composites/reveal-source.js.map +1 -1
- package/dist/features/composites/rows-model.d.ts +2 -2
- package/dist/features/composites/rows-model.js +4 -3
- package/dist/features/composites/rows-model.js.map +1 -1
- package/dist/features/composites/rows.d.ts +16 -28
- package/dist/features/composites/rows.js +20 -54
- package/dist/features/composites/rows.js.map +1 -1
- package/dist/features/composites/schema.d.ts +12 -11
- package/dist/features/composites/schema.js +10 -9
- package/dist/features/composites/schema.js.map +1 -1
- package/dist/features/composites/source.d.ts +20 -0
- package/dist/features/composites/source.js +40 -0
- package/dist/features/composites/source.js.map +1 -0
- package/dist/features/composites/split.d.ts +11 -11
- package/dist/features/composites/split.js +20 -20
- package/dist/features/composites/split.js.map +1 -1
- package/dist/features/composites/structure-mode.js +3 -3
- package/dist/features/composites/structure-mode.js.map +1 -1
- package/dist/features/composites/table-model.js +2 -2
- package/dist/features/composites/table-model.js.map +1 -1
- package/dist/features/composites/use-composite-inspector.js +3 -1
- package/dist/features/composites/use-composite-inspector.js.map +1 -1
- package/dist/features/composites/use-composite-rows.d.ts +2 -2
- package/dist/features/composites/use-composite-rows.js.map +1 -1
- package/dist/features/composites/vue.js +1 -1
- package/dist/features/composites/vue.js.map +1 -1
- package/dist/features/image-studio/components/ImageStudioDialog.js +1 -1
- package/dist/features/image-studio/components/ImageStudioDialog.js.map +1 -1
- package/dist/features/image-studio/components/ImageStudioDialog.vue.d.ts +1 -1
- package/dist/features/image-studio/components/ImageStudioView.js.map +1 -1
- package/dist/features/image-studio/feature.d.ts +1 -1
- package/dist/features/image-studio/feature.js +1 -1
- package/dist/features/image-studio/feature.js.map +1 -1
- package/dist/features/image-studio/node-core.d.ts +3 -3
- package/dist/features/image-studio/node-core.js +1 -1
- package/dist/features/image-studio/node-core.js.map +1 -1
- package/dist/features/image-studio/node-store.d.ts +1 -1
- package/dist/features/image-studio/node-store.js +1 -1
- package/dist/features/image-studio/node-store.js.map +1 -1
- package/dist/features/image-studio/react/ImageStudioDialog.d.ts +1 -1
- package/dist/features/image-studio/react/ImageStudioDialog.js +1 -1
- package/dist/features/image-studio/react/ImageStudioDialog.js.map +1 -1
- package/dist/features/image-studio/react/ImageStudioView.js +1 -1
- package/dist/features/image-studio/react/ImageStudioView.js.map +1 -1
- package/dist/features/image-studio/react/store.d.ts +3 -3
- package/dist/features/image-studio/react/store.js.map +1 -1
- package/dist/features/image-studio/react.d.ts +1 -1
- package/dist/features/image-studio/react.js +1 -1
- package/dist/features/image-studio/react.js.map +1 -1
- package/dist/features/image-studio/schema.d.ts +1 -1
- package/dist/features/image-studio/schema.js +1 -1
- package/dist/features/image-studio/schema.js.map +1 -1
- package/dist/features/image-studio/state.d.ts +3 -3
- package/dist/features/image-studio/state.js +2 -2
- package/dist/features/image-studio/state.js.map +1 -1
- package/dist/features/image-studio/store.d.ts +3 -3
- package/dist/features/image-studio/vue.d.ts +1 -1
- package/dist/features/image-studio/vue.js +1 -1
- package/dist/features/image-studio/vue.js.map +1 -1
- package/dist/features/media/index.js +1 -1
- package/dist/features/media/react/AudioRecorderModal.js +1 -1
- package/dist/features/media/react.js +1 -1
- package/dist/features/mentions/tag.js +2 -1
- package/dist/features/mentions/tag.js.map +1 -1
- package/dist/features/themes/components/SettingsAppearanceTab.js +1 -1
- package/dist/features/themes/components/SettingsAppearanceTab.js.map +1 -1
- package/dist/features/themes/feature.d.ts +1 -1
- package/dist/features/themes/feature.js.map +1 -1
- package/dist/features/themes/react/SettingsAppearanceTab.d.ts +1 -1
- package/dist/features/themes/react/SettingsAppearanceTab.js +1 -1
- package/dist/features/themes/react/SettingsAppearanceTab.js.map +1 -1
- package/dist/features/themes/theme-runtime.js +1 -1
- package/dist/features/themes/theme-runtime.js.map +1 -1
- package/dist/features/transcript/TranscriptSegmentView.js +1 -1
- package/dist/features/transcript/TranscriptSegmentView.js.map +1 -1
- package/dist/features/transcript/react/TranscriptSegmentView.js +1 -1
- package/dist/features/transcript/react/TranscriptSegmentView.js.map +1 -1
- package/dist/features/transcript/segment-node.js.map +1 -1
- package/dist/features/transfer/feature.js +1 -1
- package/dist/features/transfer/feature.js.map +1 -1
- package/dist/features/transfer/transforms.d.ts +4 -4
- package/dist/features/transfer/transforms.js +12 -12
- package/dist/features/transfer/transforms.js.map +1 -1
- package/dist/i18n/de/ai.js +4 -4
- package/dist/i18n/de/ai.js.map +1 -1
- package/dist/i18n/de/authors.js +1 -1
- package/dist/i18n/de/authors.js.map +1 -1
- package/dist/i18n/de/comments.js +1 -1
- package/dist/i18n/de/comments.js.map +1 -1
- package/dist/i18n/de/composites.js +62 -59
- package/dist/i18n/de/composites.js.map +1 -1
- package/dist/i18n/de/image-studio.js +2 -2
- package/dist/i18n/de/image-studio.js.map +1 -1
- package/dist/i18n/de/integrations.js +20 -20
- package/dist/i18n/de/integrations.js.map +1 -1
- package/dist/i18n/de/markdown.js +1 -1
- package/dist/i18n/de/markdown.js.map +1 -1
- package/dist/i18n/de/palette.js +1 -1
- package/dist/i18n/de/palette.js.map +1 -1
- package/dist/i18n/de/themes.js +3 -3
- package/dist/i18n/de/themes.js.map +1 -1
- package/dist/i18n/de/transfer.js +2 -2
- package/dist/i18n/de/transfer.js.map +1 -1
- package/dist/i18n/de/tree.js +6 -6
- package/dist/i18n/de/tree.js.map +1 -1
- package/dist/i18n/de.d.ts +101 -98
- package/dist/i18n/en/ai.js +2 -2
- package/dist/i18n/en/ai.js.map +1 -1
- package/dist/i18n/en/composites.js +64 -61
- package/dist/i18n/en/composites.js.map +1 -1
- package/dist/i18n/en/integrations.js +9 -9
- package/dist/i18n/en/integrations.js.map +1 -1
- package/dist/i18n/en/markdown.js +1 -1
- package/dist/i18n/en/markdown.js.map +1 -1
- package/dist/i18n/en/palette.js +1 -1
- package/dist/i18n/en/palette.js.map +1 -1
- package/dist/i18n/en/themes.js +4 -4
- package/dist/i18n/en/themes.js.map +1 -1
- package/dist/i18n/en/tree.js +5 -5
- package/dist/i18n/en/tree.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/integrations/composite-ai/bibliography-fetch.d.ts +6 -6
- package/dist/integrations/composite-ai/bibliography-fetch.js +19 -19
- package/dist/integrations/composite-ai/bibliography-fetch.js.map +1 -1
- package/dist/integrations/composite-ai/composite-fill.d.ts +4 -4
- package/dist/integrations/composite-ai/composite-fill.js +5 -5
- package/dist/integrations/composite-ai/composite-fill.js.map +1 -1
- package/dist/integrations/composite-ai/composite-summary.d.ts +2 -2
- package/dist/integrations/composite-ai/composite-summary.js +5 -5
- package/dist/integrations/composite-ai/composite-summary.js.map +1 -1
- package/dist/integrations/composite-ai/derive.d.ts +17 -17
- package/dist/integrations/composite-ai/derive.js +27 -26
- package/dist/integrations/composite-ai/derive.js.map +1 -1
- package/dist/integrations/composite-ai/index.d.ts +14 -15
- package/dist/integrations/composite-ai/index.js +98 -77
- package/dist/integrations/composite-ai/index.js.map +1 -1
- package/dist/integrations/composite-ai/outline-sanitize.d.ts +1 -1
- package/dist/integrations/composite-ai/outline-sanitize.js +1 -1
- package/dist/integrations/composite-ai/outline-sanitize.js.map +1 -1
- package/dist/integrations/composite-ai/rendition.d.ts +9 -9
- package/dist/integrations/composite-ai/rendition.js +27 -27
- package/dist/integrations/composite-ai/rendition.js.map +1 -1
- package/dist/integrations/composite-ai/split.d.ts +8 -8
- package/dist/integrations/composite-ai/split.js +12 -12
- package/dist/integrations/composite-ai/split.js.map +1 -1
- package/dist/integrations/composite-ai/transfer-transforms.d.ts +2 -2
- package/dist/integrations/composite-ai/transfer-transforms.js +12 -12
- package/dist/integrations/composite-ai/transfer-transforms.js.map +1 -1
- package/dist/integrations/composite-media/index.d.ts +4 -3
- package/dist/integrations/composite-media/index.js +20 -14
- package/dist/integrations/composite-media/index.js.map +1 -1
- package/dist/markdown/MarkdownSurface.vue.d.ts +7 -7
- package/dist/markdown/document.js +1 -1
- package/dist/markdown/document.js.map +1 -1
- package/dist/nuxt/module.d.ts +30 -24
- package/dist/nuxt/module.js.map +1 -1
- package/dist/nuxt/runtime/server/plugins/editor-server.js +3 -2
- package/dist/nuxt/runtime/server/plugins/editor-server.js.map +1 -1
- package/dist/presets/compose.d.ts +6 -6
- package/dist/presets/compose.js +8 -5
- package/dist/presets/compose.js.map +1 -1
- package/dist/react/AdvancedEditor.d.ts +2 -2
- package/dist/react/AdvancedEditor.js +1 -1
- package/dist/react/AdvancedEditor.js.map +1 -1
- package/dist/react/compose.d.ts +1 -1
- package/dist/react/compose.js +2 -2
- package/dist/react/compose.js.map +1 -1
- package/dist/react/composed-surface.d.ts +5 -5
- package/dist/react/composed-surface.js +2 -2
- package/dist/react/composed-surface.js.map +1 -1
- package/dist/server/ai.d.ts +7 -7
- package/dist/server/ai.js +1 -1
- package/dist/server/ai.js.map +1 -1
- package/dist/server/auth.d.ts +1 -1
- package/dist/server/collab-state.d.ts +1 -1
- package/dist/server/collab-state.js.map +1 -1
- package/dist/server/collab.d.ts +4 -4
- package/dist/server/collab.js +22 -17
- package/dist/server/collab.js.map +1 -1
- package/dist/server/handlers/ai.d.ts +9 -6
- package/dist/server/handlers/ai.js +13 -17
- package/dist/server/handlers/ai.js.map +1 -1
- package/dist/server/handlers/context.d.ts +4 -0
- package/dist/server/handlers/context.js.map +1 -1
- package/dist/server/handlers/editor.d.ts +33 -32
- package/dist/server/handlers/editor.js +13 -8
- package/dist/server/handlers/editor.js.map +1 -1
- package/dist/server/handlers/images.d.ts +1 -1
- package/dist/server/handlers/images.js +1 -1
- package/dist/server/handlers/images.js.map +1 -1
- package/dist/server/host.d.ts +4 -0
- package/dist/server/host.js +10 -2
- package/dist/server/host.js.map +1 -1
- package/dist/server/index.d.ts +3 -3
- package/dist/server/ports.d.ts +8 -8
- package/dist/server/ports.js.map +1 -1
- package/dist/settings/index.d.ts +20 -19
- package/dist/settings/index.js +25 -24
- package/dist/settings/index.js.map +1 -1
- package/dist/settings/migrate.d.ts +18 -0
- package/dist/settings/migrate.js +46 -0
- package/dist/settings/migrate.js.map +1 -0
- package/dist/settings/values.d.ts +12 -12
- package/dist/settings/values.js +11 -11
- package/dist/settings/values.js.map +1 -1
- package/dist/styles/composites.css +10 -10
- package/dist/tree/DocumentTree.js +12 -5
- package/dist/tree/DocumentTree.js.map +1 -1
- package/dist/tree/drop-rules.js +5 -5
- package/dist/tree/drop-rules.js.map +1 -1
- package/dist/tree/react/DocumentTree.js +14 -5
- package/dist/tree/react/DocumentTree.js.map +1 -1
- package/dist/tree/tree-host.js +6 -6
- package/dist/tree/tree-host.js.map +1 -1
- package/dist/tree/tree-items.js +34 -28
- package/dist/tree/tree-items.js.map +1 -1
- package/dist/tree/tree-model.js +16 -16
- package/dist/tree/tree-model.js.map +1 -1
- package/dist/tree/tree-rows.js +2 -2
- package/dist/tree/tree-rows.js.map +1 -1
- package/dist/tree/tree-view-model.d.ts +2 -2
- package/dist/tree/tree-view-model.js.map +1 -1
- package/dist/vue/AdvancedEditor.js +2 -2
- package/dist/vue/AdvancedEditor.js.map +1 -1
- package/dist/vue/AdvancedEditor.vue.d.ts +10 -10
- package/dist/vue/SimpleEditor.vue.d.ts +4 -4
- package/dist/vue/components/EditorSurface.vue.d.ts +4 -4
- package/dist/vue/compose.d.ts +1 -1
- package/dist/vue/compose.js +2 -2
- package/dist/vue/compose.js.map +1 -1
- package/package.json +1 -1
- package/dist/features/composites/derivation.d.ts +0 -62
- package/dist/features/composites/derivation.js +0 -102
- package/dist/features/composites/derivation.js.map +0 -1
- package/dist/features/composites/kinds.d.ts +0 -83
- package/dist/features/composites/kinds.js +0 -285
- package/dist/features/composites/kinds.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant.js","names":[],"sources":["../../../src/features/ai/assistant.ts"],"sourcesContent":["import type { EditorBackend } from '../../core/backend'\nimport type { AiBlock } from '../../core/feature'\nimport type { Notifier } from '../../core/notify'\nimport { createStore, type ReadonlyStore } from '../../core/store'\nimport type { Translate } from '../../i18n'\nimport type { AiLanguage,
|
|
1
|
+
{"version":3,"file":"assistant.js","names":[],"sources":["../../../src/features/ai/assistant.ts"],"sourcesContent":["import type { EditorBackend } from '../../core/backend'\nimport type { AiBlock } from '../../core/feature'\nimport type { Notifier } from '../../core/notify'\nimport { createStore, type ReadonlyStore } from '../../core/store'\nimport type { Translate } from '../../i18n'\nimport type { AiLanguage, ModelRole } from '../../settings'\nimport { postAiSse } from './ai-sse'\nimport { AI_TASKS, type AiBlockInput, type AiTaskId, type ModelRef } from './protocol'\nimport { notifyAiRateLimited } from './rate-limit'\n\nexport type AiStatus = 'idle' | 'streaming' | 'done' | 'error'\n\nexport interface AiRunBody {\n task: AiTaskId\n prompt: string\n selection: string\n context: string\n language?: AiLanguage\n /** The editor's host blocks (`aiContextOf(editor).blocks`), listed in the task's system prompt. */\n blocks?: readonly AiBlock[]\n /** The block of a `needsBlock` task (`fill-block`): its brief and material. */\n block?: AiBlockInput\n}\n\n/** Snapshot of the running or last request: its status, the streamed text so far and the error message. */\nexport interface AiAssistantState {\n status: AiStatus\n output: string\n error: string | null\n}\n\n/** What `createAiAssistant` needs from the app: the AI port, the model of a Model role, the notifier and translator for the 429 notice and failures. */\nexport interface AiAssistantOptions {\n /** `EditorContext.backend.ai`; without it every run ends in the error state (501), like a server without AI. */\n ai: EditorBackend['ai']\n modelRef: (slot: ModelRole) => ModelRef\n /** Receives the 429 notice. */\n notify: Notifier\n /** The app's translator (`EditorContext.t`). */\n t: Translate\n}\n\n/** The streaming assistant: observe `state`, `run` a task, `abort`/`reset` it. */\nexport interface AiAssistant {\n state: ReadonlyStore<AiAssistantState>\n run: (body: AiRunBody) => Promise<void>\n /** Stops the running request (its outcome is `idle`). */\n abort: () => void\n /** Aborts and returns to the empty `idle` state. */\n reset: () => void\n /** Clears the error message; the status stays. */\n clearError: () => void\n}\n\nconst IDLE: AiAssistantState = { status: 'idle', output: '', error: null }\n\n/** Streams the backend's `generate` (SSE: `delta` / `done` / `error` events) into a store, on the task's Model role. */\nexport function createAiAssistant({ ai, modelRef, notify, t }: AiAssistantOptions): AiAssistant {\n const store = createStore<AiAssistantState>(IDLE)\n let controller: AbortController | null = null\n\n function abort() {\n controller?.abort()\n }\n\n function reset() {\n abort()\n controller = null\n store.set(IDLE)\n }\n\n function clearError() {\n const state = store.get()\n if (state.error !== null) store.set({ ...state, error: null })\n }\n\n async function run(body: AiRunBody): Promise<void> {\n reset()\n const own = new AbortController()\n controller = own\n store.set({ status: 'streaming', output: '', error: null })\n const outcome = await postAiSse(ai, 'generate', { ...body, model: modelRef(AI_TASKS[body.task].slot) }, {\n signal: own.signal,\n t,\n onDelta: (text) => {\n if (controller === own) store.set({ ...store.get(), output: store.get().output + text })\n },\n })\n if (controller !== own) return // superseded by reset()/another run\n controller = null\n if (outcome.status === 'done') {\n store.set({ ...store.get(), status: 'done' })\n }\n else if (outcome.status === 'error') {\n store.set({ ...store.get(), status: 'error', error: outcome.message })\n }\n else {\n // Notice instead of the error state on 429, so the caller stays ready for another try.\n if (outcome.status === 'rate-limited') notifyAiRateLimited(notify, t)\n store.set({ ...store.get(), status: 'idle' })\n }\n }\n\n return { state: store, run, abort, reset, clearError }\n}\n"],"mappings":";;;;;AAsDA,MAAM,OAAyB;CAAE,QAAQ;CAAQ,QAAQ;CAAI,OAAO;AAAK;;AAGzE,SAAgB,kBAAkB,EAAE,IAAI,UAAU,QAAQ,KAAsC;CAC9F,MAAM,QAAQ,YAA8B,IAAI;CAChD,IAAI,aAAqC;CAEzC,SAAS,QAAQ;EACf,YAAY,MAAM;CACpB;CAEA,SAAS,QAAQ;EACf,MAAM;EACN,aAAa;EACb,MAAM,IAAI,IAAI;CAChB;CAEA,SAAS,aAAa;EACpB,MAAM,QAAQ,MAAM,IAAI;EACxB,IAAI,MAAM,UAAU,MAAM,MAAM,IAAI;GAAE,GAAG;GAAO,OAAO;EAAK,CAAC;CAC/D;CAEA,eAAe,IAAI,MAAgC;EACjD,MAAM;EACN,MAAM,MAAM,IAAI,gBAAgB;EAChC,aAAa;EACb,MAAM,IAAI;GAAE,QAAQ;GAAa,QAAQ;GAAI,OAAO;EAAK,CAAC;EAC1D,MAAM,UAAU,MAAM,UAAU,IAAI,YAAY;GAAE,GAAG;GAAM,OAAO,SAAS,SAAS,KAAK,KAAK,CAAC,IAAI;EAAE,GAAG;GACtG,QAAQ,IAAI;GACZ;GACA,UAAU,SAAS;IACjB,IAAI,eAAe,KAAK,MAAM,IAAI;KAAE,GAAG,MAAM,IAAI;KAAG,QAAQ,MAAM,IAAI,CAAC,CAAC,SAAS;IAAK,CAAC;GACzF;EACF,CAAC;EACD,IAAI,eAAe,KAAK;EACxB,aAAa;EACb,IAAI,QAAQ,WAAW,QACrB,MAAM,IAAI;GAAE,GAAG,MAAM,IAAI;GAAG,QAAQ;EAAO,CAAC;OAEzC,IAAI,QAAQ,WAAW,SAC1B,MAAM,IAAI;GAAE,GAAG,MAAM,IAAI;GAAG,QAAQ;GAAS,OAAO,QAAQ;EAAQ,CAAC;OAElE;GAEH,IAAI,QAAQ,WAAW,gBAAgB,oBAAoB,QAAQ,CAAC;GACpE,MAAM,IAAI;IAAE,GAAG,MAAM,IAAI;IAAG,QAAQ;GAAO,CAAC;EAC9C;CACF;CAEA,OAAO;EAAE,OAAO;EAAO;EAAK;EAAO;EAAO;CAAW;AACvD"}
|
|
@@ -180,7 +180,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
180
180
|
})
|
|
181
181
|
}, {
|
|
182
182
|
content: withCtx(() => [unref(state).picking ? (openBlock(), createElementBlock("div", _hoisted_2, [
|
|
183
|
-
createCommentVNode(" Caret mode generates blocks, selection mode rewrites text in the block: each has its own
|
|
183
|
+
createCommentVNode(" Caret mode generates blocks, selection mode rewrites text in the block: each has its own Model role. "),
|
|
184
184
|
createElementVNode("div", _hoisted_3, [createElementVNode("span", _hoisted_4, toDisplayString(unref(t)("ai.menu.model")), 1), createVNode(_sfc_main$1, {
|
|
185
185
|
slot: unref(state).mode === "caret" ? "generate" : "rewrite",
|
|
186
186
|
size: "xs",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiSelectionMenu.js","names":["_openBlock","_createElementBlock","_Fragment","_createVNode","_unref","_withCtx","_createElementVNode","_createCommentVNode","_toDisplayString","ModelQuickSwitch","_renderList","_createBlock","_withModifiers"],"sources":["../../../../src/features/ai/components/AiSelectionMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { BubbleMenuPluginProps } from '@tiptap/extension-bubble-menu'\nimport type { EditorState } from '@tiptap/pm/state'\nimport { type Editor, EditorContent, useEditor } from '@tiptap/vue-3'\nimport { BubbleMenu } from '@tiptap/vue-3/menus'\nimport { computed, onBeforeUnmount, useTemplateRef, watch } from 'vue'\nimport { parseBlocks, resolveRange } from '../../../core'\nimport { useEditorSettings } from '../../../vue/settings'\nimport type { InputExposed } from '../../../vue/kit/types'\nimport { useUiKit } from '../../../vue/kit/use-ui-kit'\nimport { useStoreRef } from '../../../vue/store-ref'\nimport { useNotifier } from '../../../vue/use-notifier'\nimport { useEditorI18n } from '../../../vue/use-editor-i18n'\nimport { AI_LANGUAGES } from '../../../settings'\nimport { aiSelectionHighlightKey } from '../ai-selection-highlight'\nimport { previewExtensions } from '../preview-extensions'\nimport { AI_LANGUAGE_KEYS } from '../protocol'\nimport { AI_SELECTION_MENU_KEY, createAiSelectionFlow } from '../selection-flow'\nimport { useAiAssistant } from '../use-ai-assistant'\nimport ModelQuickSwitch from './ModelQuickSwitch.vue'\n\n/**\n * AI quick actions on a text selection: a bubble menu entry opens a popover with the selection tasks of the registry\n * (`selectionMenu`), the result streams into a preview and is applied over the range captured when the menu opened.\n * Caret mode (`/ai`, see `openAiMenuAtCaret`): the same popover opens at the caret with the `caretMenu` tasks and\n * `generate` as free prompt; the result is inserted at the caret line (`insertAtCaretLine`).\n * Needs the AiSelectionHighlight extension on the editor. The flow (`createAiSelectionFlow`) owns every step; this\n * component renders its state, places the popover and shows the preview.\n */\nconst props = defineProps<{ editor: Editor }>()\n\nconst { Alert: UAlert, Button: UButton, Icon: UIcon, Input: UInput, Popover: UPopover, Select: USelect } = useUiKit()\nconst notify = useNotifier(() => props.editor)\nconst { t } = useEditorI18n()\nconst { model: assistant } = useAiAssistant(() => props.editor)\nconst { settings } = useEditorSettings()\nconst flow = createAiSelectionFlow({ assistant, notify, t, editor: () => props.editor, language: () => settings.value.ai.translateLanguage })\nconst state = useStoreRef(flow.state)\n\nconst languageItems = computed(() => AI_LANGUAGES.map(l => ({ label: t(AI_LANGUAGE_KEYS[l]), value: l })))\nconst prompt = computed({ get: () => state.value.prompt, set: flow.setPrompt })\nconst language = computed({ get: () => state.value.language, set: flow.setLanguage })\nconst promptInput = useTemplateRef<InputExposed>('promptInput')\nconst requestLabel = computed(() => {\n const request = state.value.request\n if (!request) return undefined\n const task = t(request.task.labelKey)\n return request.language ? t('ai.menu.requestWithLanguage', { task, language: t(AI_LANGUAGE_KEYS[request.language]) }) : task\n})\n// Extra rows other features contribute (`aiMenuActions` of their extensions), offered while the selection qualifies.\nconst menuActions = computed(() => state.value.open ? flow.menuActions() : [])\n\nconst shouldShow: NonNullable<BubbleMenuPluginProps['shouldShow']> = ({ element, view }) =>\n (view.hasFocus() || element.contains(document.activeElement)) && flow.offersSelection()\n\n/** Caret mode: the prompt input gets the focus, so the instruction can be typed right away. */\nfunction onOpenAutoFocus(event: Event) {\n if (state.value.mode !== 'caret') return\n event.preventDefault()\n promptInput.value?.inputRef?.focus()\n}\n\n\n// Popover anchor: the highlighted range (its plugin state follows local and remote edits); in caret mode the caret.\nlet anchorRect = new DOMRect()\nconst reference = {\n getBoundingClientRect(): DOMRect {\n const { editor } = props\n if (editor.isDestroyed) return anchorRect\n if (state.value.mode === 'caret') return caretRect(editor)\n const highlight = aiSelectionHighlightKey.getState(editor.state)\n const highlighted = highlight && resolveRange(editor.state, highlight.anchor)\n if (!highlighted || highlighted.from >= highlighted.to) return anchorRect\n const { view } = editor\n const start = view.coordsAtPos(highlighted.from, 1)\n const end = view.coordsAtPos(highlighted.to, -1)\n // Across lines the range spans the editor's width.\n const bounds = view.dom.getBoundingClientRect()\n const oneLine = end.top < start.bottom\n const left = oneLine ? start.left : bounds.left\n const right = oneLine ? end.right : bounds.right\n anchorRect = new DOMRect(left, start.top, Math.max(right - left, 1), end.bottom - start.top)\n return anchorRect\n },\n get contextElement() {\n return props.editor.view.dom\n },\n}\n\n// The caret's position is resolved from its anchor once per editor state (the anchor is measured every frame).\nlet caretAt: { state: EditorState, pos: number | null } | null = null\nfunction caretRect(editor: Editor): DOMRect {\n if (caretAt?.state !== editor.state) caretAt = { state: editor.state, pos: flow.range()?.from ?? null }\n if (caretAt.pos === null) return anchorRect\n const coords = editor.view.coordsAtPos(caretAt.pos)\n anchorRect = new DOMRect(coords.left, coords.top, 1, coords.bottom - coords.top)\n return anchorRect\n}\n\nconst preview = useEditor({\n editable: false,\n extensions: previewExtensions(props.editor),\n editorProps: { attributes: { class: 'tiptap ai-selection-preview' } },\n})\n\n// Coalesce streamed deltas: re-parse the Markdown at most every 80 ms; speaker lines show as segments, as applied.\nlet previewTimer: ReturnType<typeof setTimeout> | undefined\nwatch(() => state.value.output, () => {\n if (previewTimer) return\n previewTimer = setTimeout(() => {\n previewTimer = undefined\n const instance = preview.value\n if (!instance) return\n instance.commands.setContent({ type: 'doc', content: parseBlocks(props.editor, state.value.output).blocks }, { emitUpdate: false })\n }, 80)\n})\n\nonBeforeUnmount(() => {\n clearTimeout(previewTimer)\n flow.dispose()\n preview.value?.destroy()\n})\n</script>\n\n<template>\n <BubbleMenu :editor=\"editor\" :plugin-key=\"AI_SELECTION_MENU_KEY\" :should-show=\"shouldShow\" :options=\"{ placement: 'top', offset: 8 }\" class=\"z-10\">\n <div class=\"flex rounded-md border border-[var(--sk-border)] bg-[var(--sk-bg)] p-0.5 shadow-md\">\n <UButton size=\"sm\" color=\"neutral\" variant=\"ghost\" icon=\"i-lucide-sparkles\" :label=\"t('ai.menu.trigger')\" @click=\"flow.openForSelection()\" />\n </div>\n </BubbleMenu>\n\n <UPopover\n :open=\"state.open\"\n :reference=\"reference\"\n :dismissible=\"state.picking\"\n :content=\"{ side: 'bottom', align: 'start', updatePositionStrategy: 'always', onOpenAutoFocus }\"\n :ui=\"{ content: 'w-[30rem] max-w-[calc(100vw-2rem)]' }\"\n @update:open=\"(value: boolean) => { if (!value) flow.close(state.mode === 'caret') }\"\n >\n <template #content>\n <div v-if=\"state.picking\" class=\"flex flex-col gap-1 p-2\">\n <!-- Caret mode generates blocks, selection mode rewrites text in the block: each has its own model slot. -->\n <div class=\"flex items-center justify-end gap-2 px-1 pb-1\">\n <span class=\"text-xs text-[var(--sk-muted)]\">{{ t('ai.menu.model') }}</span>\n <ModelQuickSwitch :slot=\"state.mode === 'caret' ? 'generate' : 'rewrite'\" size=\"xs\" class=\"w-56\" />\n </div>\n <div v-for=\"task in state.actions\" :key=\"task.id\" class=\"flex items-center gap-1\">\n <UButton\n :icon=\"task.icon\"\n :label=\"t(task.labelKey)\"\n color=\"neutral\"\n variant=\"ghost\"\n class=\"flex-1 justify-start\"\n :disabled=\"state.mode === 'caret' && task.needsSelection && !state.hasTextBefore\"\n @click=\"flow.start(task)\"\n />\n <USelect v-if=\"task.needsLanguage\" v-model=\"language\" :items=\"languageItems\" size=\"sm\" class=\"w-36\" :aria-label=\"t('ai.menu.targetLanguage')\" />\n </div>\n <UButton\n v-for=\"action in menuActions\"\n :key=\"action.id\"\n :icon=\"action.icon\"\n :label=\"action.label\"\n color=\"neutral\"\n variant=\"ghost\"\n class=\"justify-start\"\n :loading=\"state.runningAction === action.id\"\n :disabled=\"state.runningAction !== null && state.runningAction !== action.id\"\n @click=\"flow.runAction(action)\"\n />\n <form class=\"mt-1 flex gap-1 border-t border-[var(--sk-border)] pt-2\" @submit.prevent=\"flow.submitPrompt()\">\n <UInput ref=\"promptInput\" v-model=\"prompt\" :icon=\"state.freePrompt.icon\" :placeholder=\"state.freePrompt.promptLabelKey && t(state.freePrompt.promptLabelKey)\" class=\"flex-1\" />\n <UButton type=\"submit\" icon=\"i-lucide-arrow-up\" :disabled=\"!state.prompt.trim()\" :aria-label=\"t('ai.menu.sendInstruction')\" />\n </form>\n </div>\n\n <div v-else class=\"flex flex-col gap-3 p-3\">\n <div class=\"flex items-center gap-2 text-sm font-medium\">\n <UIcon v-if=\"state.request\" :name=\"state.request.task.icon\" class=\"size-4\" />\n <span class=\"flex-1 truncate\">{{ requestLabel }}</span>\n <UIcon v-if=\"state.status === 'streaming'\" name=\"i-lucide-loader-circle\" class=\"size-4 animate-spin text-[var(--sk-muted)]\" />\n </div>\n <UAlert v-if=\"state.error\" color=\"error\" variant=\"subtle\" :title=\"state.error\" />\n <div class=\"max-h-72 min-h-16 overflow-auto rounded-md border border-[var(--sk-border)] p-3 text-sm\">\n <EditorContent v-if=\"preview\" :editor=\"preview\" />\n </div>\n <div class=\"flex flex-wrap justify-end gap-2\">\n <UButton v-if=\"state.status === 'streaming'\" size=\"sm\" color=\"neutral\" variant=\"ghost\" :label=\"t('ai.menu.cancel')\" @click=\"flow.abort()\" />\n <UButton size=\"sm\" color=\"neutral\" variant=\"ghost\" :label=\"t('ai.menu.discard')\" @click=\"flow.close(true)\" />\n <UButton\n size=\"sm\"\n color=\"neutral\"\n variant=\"outline\"\n icon=\"i-lucide-rotate-ccw\"\n :label=\"t('ai.menu.retry')\"\n :disabled=\"state.status === 'streaming'\"\n @click=\"flow.retry()\"\n />\n <UButton v-if=\"state.mode === 'caret'\" size=\"sm\" icon=\"i-lucide-text-cursor-input\" :label=\"t('ai.menu.insert')\" :disabled=\"!state.canApply\" @click=\"flow.insertAtCaret()\" />\n <template v-else>\n <UButton\n size=\"sm\"\n color=\"neutral\"\n variant=\"outline\"\n icon=\"i-lucide-list-plus\"\n :label=\"t('ai.menu.insertBelow')\"\n :disabled=\"!state.canApply\"\n @click=\"flow.apply('insert-below')\"\n />\n <UButton size=\"sm\" icon=\"i-lucide-replace\" :label=\"t('ai.menu.replace')\" :disabled=\"!state.canApply\" @click=\"flow.apply('replace')\" />\n </template>\n </div>\n </div>\n </template>\n </UPopover>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AiSelectionMenu.js","names":["_openBlock","_createElementBlock","_Fragment","_createVNode","_unref","_withCtx","_createElementVNode","_createCommentVNode","_toDisplayString","ModelQuickSwitch","_renderList","_createBlock","_withModifiers"],"sources":["../../../../src/features/ai/components/AiSelectionMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { BubbleMenuPluginProps } from '@tiptap/extension-bubble-menu'\nimport type { EditorState } from '@tiptap/pm/state'\nimport { type Editor, EditorContent, useEditor } from '@tiptap/vue-3'\nimport { BubbleMenu } from '@tiptap/vue-3/menus'\nimport { computed, onBeforeUnmount, useTemplateRef, watch } from 'vue'\nimport { parseBlocks, resolveRange } from '../../../core'\nimport { useEditorSettings } from '../../../vue/settings'\nimport type { InputExposed } from '../../../vue/kit/types'\nimport { useUiKit } from '../../../vue/kit/use-ui-kit'\nimport { useStoreRef } from '../../../vue/store-ref'\nimport { useNotifier } from '../../../vue/use-notifier'\nimport { useEditorI18n } from '../../../vue/use-editor-i18n'\nimport { AI_LANGUAGES } from '../../../settings'\nimport { aiSelectionHighlightKey } from '../ai-selection-highlight'\nimport { previewExtensions } from '../preview-extensions'\nimport { AI_LANGUAGE_KEYS } from '../protocol'\nimport { AI_SELECTION_MENU_KEY, createAiSelectionFlow } from '../selection-flow'\nimport { useAiAssistant } from '../use-ai-assistant'\nimport ModelQuickSwitch from './ModelQuickSwitch.vue'\n\n/**\n * AI quick actions on a text selection: a bubble menu entry opens a popover with the selection tasks of the registry\n * (`selectionMenu`), the result streams into a preview and is applied over the range captured when the menu opened.\n * Caret mode (`/ai`, see `openAiMenuAtCaret`): the same popover opens at the caret with the `caretMenu` tasks and\n * `generate` as free prompt; the result is inserted at the caret line (`insertAtCaretLine`).\n * Needs the AiSelectionHighlight extension on the editor. The flow (`createAiSelectionFlow`) owns every step; this\n * component renders its state, places the popover and shows the preview.\n */\nconst props = defineProps<{ editor: Editor }>()\n\nconst { Alert: UAlert, Button: UButton, Icon: UIcon, Input: UInput, Popover: UPopover, Select: USelect } = useUiKit()\nconst notify = useNotifier(() => props.editor)\nconst { t } = useEditorI18n()\nconst { model: assistant } = useAiAssistant(() => props.editor)\nconst { settings } = useEditorSettings()\nconst flow = createAiSelectionFlow({ assistant, notify, t, editor: () => props.editor, language: () => settings.value.ai.translateLanguage })\nconst state = useStoreRef(flow.state)\n\nconst languageItems = computed(() => AI_LANGUAGES.map(l => ({ label: t(AI_LANGUAGE_KEYS[l]), value: l })))\nconst prompt = computed({ get: () => state.value.prompt, set: flow.setPrompt })\nconst language = computed({ get: () => state.value.language, set: flow.setLanguage })\nconst promptInput = useTemplateRef<InputExposed>('promptInput')\nconst requestLabel = computed(() => {\n const request = state.value.request\n if (!request) return undefined\n const task = t(request.task.labelKey)\n return request.language ? t('ai.menu.requestWithLanguage', { task, language: t(AI_LANGUAGE_KEYS[request.language]) }) : task\n})\n// Extra rows other features contribute (`aiMenuActions` of their extensions), offered while the selection qualifies.\nconst menuActions = computed(() => state.value.open ? flow.menuActions() : [])\n\nconst shouldShow: NonNullable<BubbleMenuPluginProps['shouldShow']> = ({ element, view }) =>\n (view.hasFocus() || element.contains(document.activeElement)) && flow.offersSelection()\n\n/** Caret mode: the prompt input gets the focus, so the instruction can be typed right away. */\nfunction onOpenAutoFocus(event: Event) {\n if (state.value.mode !== 'caret') return\n event.preventDefault()\n promptInput.value?.inputRef?.focus()\n}\n\n\n// Popover anchor: the highlighted range (its plugin state follows local and remote edits); in caret mode the caret.\nlet anchorRect = new DOMRect()\nconst reference = {\n getBoundingClientRect(): DOMRect {\n const { editor } = props\n if (editor.isDestroyed) return anchorRect\n if (state.value.mode === 'caret') return caretRect(editor)\n const highlight = aiSelectionHighlightKey.getState(editor.state)\n const highlighted = highlight && resolveRange(editor.state, highlight.anchor)\n if (!highlighted || highlighted.from >= highlighted.to) return anchorRect\n const { view } = editor\n const start = view.coordsAtPos(highlighted.from, 1)\n const end = view.coordsAtPos(highlighted.to, -1)\n // Across lines the range spans the editor's width.\n const bounds = view.dom.getBoundingClientRect()\n const oneLine = end.top < start.bottom\n const left = oneLine ? start.left : bounds.left\n const right = oneLine ? end.right : bounds.right\n anchorRect = new DOMRect(left, start.top, Math.max(right - left, 1), end.bottom - start.top)\n return anchorRect\n },\n get contextElement() {\n return props.editor.view.dom\n },\n}\n\n// The caret's position is resolved from its anchor once per editor state (the anchor is measured every frame).\nlet caretAt: { state: EditorState, pos: number | null } | null = null\nfunction caretRect(editor: Editor): DOMRect {\n if (caretAt?.state !== editor.state) caretAt = { state: editor.state, pos: flow.range()?.from ?? null }\n if (caretAt.pos === null) return anchorRect\n const coords = editor.view.coordsAtPos(caretAt.pos)\n anchorRect = new DOMRect(coords.left, coords.top, 1, coords.bottom - coords.top)\n return anchorRect\n}\n\nconst preview = useEditor({\n editable: false,\n extensions: previewExtensions(props.editor),\n editorProps: { attributes: { class: 'tiptap ai-selection-preview' } },\n})\n\n// Coalesce streamed deltas: re-parse the Markdown at most every 80 ms; speaker lines show as segments, as applied.\nlet previewTimer: ReturnType<typeof setTimeout> | undefined\nwatch(() => state.value.output, () => {\n if (previewTimer) return\n previewTimer = setTimeout(() => {\n previewTimer = undefined\n const instance = preview.value\n if (!instance) return\n instance.commands.setContent({ type: 'doc', content: parseBlocks(props.editor, state.value.output).blocks }, { emitUpdate: false })\n }, 80)\n})\n\nonBeforeUnmount(() => {\n clearTimeout(previewTimer)\n flow.dispose()\n preview.value?.destroy()\n})\n</script>\n\n<template>\n <BubbleMenu :editor=\"editor\" :plugin-key=\"AI_SELECTION_MENU_KEY\" :should-show=\"shouldShow\" :options=\"{ placement: 'top', offset: 8 }\" class=\"z-10\">\n <div class=\"flex rounded-md border border-[var(--sk-border)] bg-[var(--sk-bg)] p-0.5 shadow-md\">\n <UButton size=\"sm\" color=\"neutral\" variant=\"ghost\" icon=\"i-lucide-sparkles\" :label=\"t('ai.menu.trigger')\" @click=\"flow.openForSelection()\" />\n </div>\n </BubbleMenu>\n\n <UPopover\n :open=\"state.open\"\n :reference=\"reference\"\n :dismissible=\"state.picking\"\n :content=\"{ side: 'bottom', align: 'start', updatePositionStrategy: 'always', onOpenAutoFocus }\"\n :ui=\"{ content: 'w-[30rem] max-w-[calc(100vw-2rem)]' }\"\n @update:open=\"(value: boolean) => { if (!value) flow.close(state.mode === 'caret') }\"\n >\n <template #content>\n <div v-if=\"state.picking\" class=\"flex flex-col gap-1 p-2\">\n <!-- Caret mode generates blocks, selection mode rewrites text in the block: each has its own Model role. -->\n <div class=\"flex items-center justify-end gap-2 px-1 pb-1\">\n <span class=\"text-xs text-[var(--sk-muted)]\">{{ t('ai.menu.model') }}</span>\n <ModelQuickSwitch :slot=\"state.mode === 'caret' ? 'generate' : 'rewrite'\" size=\"xs\" class=\"w-56\" />\n </div>\n <div v-for=\"task in state.actions\" :key=\"task.id\" class=\"flex items-center gap-1\">\n <UButton\n :icon=\"task.icon\"\n :label=\"t(task.labelKey)\"\n color=\"neutral\"\n variant=\"ghost\"\n class=\"flex-1 justify-start\"\n :disabled=\"state.mode === 'caret' && task.needsSelection && !state.hasTextBefore\"\n @click=\"flow.start(task)\"\n />\n <USelect v-if=\"task.needsLanguage\" v-model=\"language\" :items=\"languageItems\" size=\"sm\" class=\"w-36\" :aria-label=\"t('ai.menu.targetLanguage')\" />\n </div>\n <UButton\n v-for=\"action in menuActions\"\n :key=\"action.id\"\n :icon=\"action.icon\"\n :label=\"action.label\"\n color=\"neutral\"\n variant=\"ghost\"\n class=\"justify-start\"\n :loading=\"state.runningAction === action.id\"\n :disabled=\"state.runningAction !== null && state.runningAction !== action.id\"\n @click=\"flow.runAction(action)\"\n />\n <form class=\"mt-1 flex gap-1 border-t border-[var(--sk-border)] pt-2\" @submit.prevent=\"flow.submitPrompt()\">\n <UInput ref=\"promptInput\" v-model=\"prompt\" :icon=\"state.freePrompt.icon\" :placeholder=\"state.freePrompt.promptLabelKey && t(state.freePrompt.promptLabelKey)\" class=\"flex-1\" />\n <UButton type=\"submit\" icon=\"i-lucide-arrow-up\" :disabled=\"!state.prompt.trim()\" :aria-label=\"t('ai.menu.sendInstruction')\" />\n </form>\n </div>\n\n <div v-else class=\"flex flex-col gap-3 p-3\">\n <div class=\"flex items-center gap-2 text-sm font-medium\">\n <UIcon v-if=\"state.request\" :name=\"state.request.task.icon\" class=\"size-4\" />\n <span class=\"flex-1 truncate\">{{ requestLabel }}</span>\n <UIcon v-if=\"state.status === 'streaming'\" name=\"i-lucide-loader-circle\" class=\"size-4 animate-spin text-[var(--sk-muted)]\" />\n </div>\n <UAlert v-if=\"state.error\" color=\"error\" variant=\"subtle\" :title=\"state.error\" />\n <div class=\"max-h-72 min-h-16 overflow-auto rounded-md border border-[var(--sk-border)] p-3 text-sm\">\n <EditorContent v-if=\"preview\" :editor=\"preview\" />\n </div>\n <div class=\"flex flex-wrap justify-end gap-2\">\n <UButton v-if=\"state.status === 'streaming'\" size=\"sm\" color=\"neutral\" variant=\"ghost\" :label=\"t('ai.menu.cancel')\" @click=\"flow.abort()\" />\n <UButton size=\"sm\" color=\"neutral\" variant=\"ghost\" :label=\"t('ai.menu.discard')\" @click=\"flow.close(true)\" />\n <UButton\n size=\"sm\"\n color=\"neutral\"\n variant=\"outline\"\n icon=\"i-lucide-rotate-ccw\"\n :label=\"t('ai.menu.retry')\"\n :disabled=\"state.status === 'streaming'\"\n @click=\"flow.retry()\"\n />\n <UButton v-if=\"state.mode === 'caret'\" size=\"sm\" icon=\"i-lucide-text-cursor-input\" :label=\"t('ai.menu.insert')\" :disabled=\"!state.canApply\" @click=\"flow.insertAtCaret()\" />\n <template v-else>\n <UButton\n size=\"sm\"\n color=\"neutral\"\n variant=\"outline\"\n icon=\"i-lucide-list-plus\"\n :label=\"t('ai.menu.insertBelow')\"\n :disabled=\"!state.canApply\"\n @click=\"flow.apply('insert-below')\"\n />\n <UButton size=\"sm\" icon=\"i-lucide-replace\" :label=\"t('ai.menu.replace')\" :disabled=\"!state.canApply\" @click=\"flow.apply('replace')\" />\n </template>\n </div>\n </div>\n </template>\n </UPopover>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MODEL_ROLE_KEYS } from "../protocol/models.js";
|
|
2
2
|
import { useUiKit } from "../../../vue/kit/use-ui-kit.js";
|
|
3
3
|
import { useEditorSettings } from "../../../vue/settings.js";
|
|
4
4
|
import { useEditorI18n } from "../../../vue/use-editor-i18n.js";
|
|
@@ -7,8 +7,8 @@ import { useModelProfiles } from "../use-model-profiles.js";
|
|
|
7
7
|
import { computed, createBlock, defineComponent, openBlock, ref, unref } from "vue";
|
|
8
8
|
//#region src/features/ai/components/ModelQuickSwitch.vue
|
|
9
9
|
/**
|
|
10
|
-
* Model profile an AI
|
|
11
|
-
* to every feature of the
|
|
10
|
+
* Model profile an AI Model role runs on. A quick switch *is* the Model role setting (`settings.ai.roles[slot]`): the choice applies
|
|
11
|
+
* to every feature of the Model role, not just to the surrounding dialog. The trailing „Modelle verwalten…“ opens the
|
|
12
12
|
* settings on the „KI“ tab. Inside an editor surface the chrome comes from its provide; mounted beside one, pass its
|
|
13
13
|
* `editor`.
|
|
14
14
|
*/
|
|
@@ -22,7 +22,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
22
22
|
},
|
|
23
23
|
setup(__props) {
|
|
24
24
|
const props = __props;
|
|
25
|
-
/** Item value of „Modelle verwalten…“; profile ids are preset ids (camelCase) or UUIDs, so it never collides. */
|
|
25
|
+
/** Item value of „Modelle verwalten…“; profile ids are Model preset ids (camelCase) or UUIDs, so it never collides. */
|
|
26
26
|
const { SelectMenu: USelectMenu } = useUiKit();
|
|
27
27
|
const { settings } = useEditorSettings();
|
|
28
28
|
const { profiles, slotProfile } = useModelProfiles();
|
|
@@ -44,7 +44,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
44
44
|
const selected = computed({
|
|
45
45
|
get: () => current.value?.id,
|
|
46
46
|
set: (id) => {
|
|
47
|
-
if (id && id !== MANAGE) settings.value.ai.
|
|
47
|
+
if (id && id !== MANAGE) settings.value.ai.roles[props.slot] = id;
|
|
48
48
|
}
|
|
49
49
|
});
|
|
50
50
|
function manage(event) {
|
|
@@ -63,8 +63,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
63
63
|
size: props.size,
|
|
64
64
|
"search-input": false,
|
|
65
65
|
icon: current.value?.source === "user" ? "i-lucide-key-round" : "i-lucide-server",
|
|
66
|
-
placeholder: unref(t)(unref(
|
|
67
|
-
"aria-label": unref(t)("ai.slot.ariaLabel", { slot: unref(t)(unref(
|
|
66
|
+
placeholder: unref(t)(unref(MODEL_ROLE_KEYS)[props.slot].labelKey),
|
|
67
|
+
"aria-label": unref(t)("ai.slot.ariaLabel", { slot: unref(t)(unref(MODEL_ROLE_KEYS)[props.slot].labelKey) }),
|
|
68
68
|
ui: { content: "min-w-72" }
|
|
69
69
|
}, null, 8, [
|
|
70
70
|
"modelValue",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModelQuickSwitch.js","names":["_openBlock","_createBlock","_unref"],"sources":["../../../../src/features/ai/components/ModelQuickSwitch.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { Editor } from '@tiptap/core'\nimport { computed, ref } from 'vue'\nimport type { SelectItem } from '../../../vue/kit/types'\nimport { useUiKit } from '../../../vue/kit/use-ui-kit'\nimport { useEditorSettings } from '../../../vue/settings'\nimport { useEditorUi } from '../../../vue/use-editor-ui'\nimport { useEditorI18n } from '../../../vue/use-editor-i18n'\nimport type {
|
|
1
|
+
{"version":3,"file":"ModelQuickSwitch.js","names":["_openBlock","_createBlock","_unref"],"sources":["../../../../src/features/ai/components/ModelQuickSwitch.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { Editor } from '@tiptap/core'\nimport { computed, ref } from 'vue'\nimport type { SelectItem } from '../../../vue/kit/types'\nimport { useUiKit } from '../../../vue/kit/use-ui-kit'\nimport { useEditorSettings } from '../../../vue/settings'\nimport { useEditorUi } from '../../../vue/use-editor-ui'\nimport { useEditorI18n } from '../../../vue/use-editor-i18n'\nimport type { ModelRole } from '../../../settings'\nimport { MODEL_ROLE_KEYS } from '../protocol'\nimport { useModelProfiles } from '../use-model-profiles'\n\n/**\n * Model profile an AI Model role runs on. A quick switch *is* the Model role setting (`settings.ai.roles[slot]`): the choice applies\n * to every feature of the Model role, not just to the surrounding dialog. The trailing „Modelle verwalten…“ opens the\n * settings on the „KI“ tab. Inside an editor surface the chrome comes from its provide; mounted beside one, pass its\n * `editor`.\n */\nconst props = withDefaults(defineProps<{\n slot: ModelRole\n size?: 'xs' | 'sm'\n /** The editor whose settings modal „Modelle verwalten…“ opens, when not mounted inside its editor surface. */\n editor?: Editor\n}>(), { size: 'sm' })\n\n/** Item value of „Modelle verwalten…“; profile ids are Model preset ids (camelCase) or UUIDs, so it never collides. */\nconst MANAGE = '__manage__'\n\nconst { SelectMenu: USelectMenu } = useUiKit()\nconst { settings } = useEditorSettings()\nconst { profiles, slotProfile } = useModelProfiles()\nconst { t } = useEditorI18n()\nconst editorUi = useEditorUi(() => props.editor)\nconst open = ref(false)\n\nconst items = computed<SelectItem[]>(() => [\n ...profiles.value.map(profile => ({\n label: profile.label,\n description: profile.model,\n icon: profile.source === 'preset' ? 'i-lucide-server' : 'i-lucide-key-round',\n value: profile.id,\n })),\n ...(editorUi.value\n ? [{ type: 'separator' as const }, { label: t('ai.slot.manage'), icon: 'i-lucide-settings-2', value: MANAGE, onSelect: manage }]\n : []),\n])\n\nconst current = computed(() => slotProfile(props.slot))\nconst selected = computed<string | undefined>({\n get: () => current.value?.id,\n set: (id) => {\n if (id && id !== MANAGE) settings.value.ai.roles[props.slot] = id\n },\n})\n\nfunction manage(event: Event) {\n // Not a selection: keep the Model role as it is.\n event.preventDefault()\n open.value = false\n editorUi.value?.openSettings('ai')\n}\n</script>\n\n<template>\n <USelectMenu\n v-model=\"selected\"\n v-model:open=\"open\"\n :items=\"items\"\n value-key=\"value\"\n :size=\"props.size\"\n :search-input=\"false\"\n :icon=\"current?.source === 'user' ? 'i-lucide-key-round' : 'i-lucide-server'\"\n :placeholder=\"t(MODEL_ROLE_KEYS[props.slot].labelKey)\"\n :aria-label=\"t('ai.slot.ariaLabel', { slot: t(MODEL_ROLE_KEYS[props.slot].labelKey) })\"\n :ui=\"{ content: 'min-w-72' }\"\n />\n</template>\n"],"mappings":";;;;;;;;;;;;;;AA0BA,MAAM,SAAS;;;;;;;;;EARf,MAAM,QAAQ;;EAUd,MAAM,EAAE,YAAY,gBAAgB,SAAS;EAC7C,MAAM,EAAE,aAAa,kBAAkB;EACvC,MAAM,EAAE,UAAU,gBAAgB,iBAAiB;EACnD,MAAM,EAAE,MAAM,cAAc;EAC5B,MAAM,WAAW,kBAAkB,MAAM,MAAM;EAC/C,MAAM,OAAO,IAAI,KAAK;EAEtB,MAAM,QAAQ,eAA6B,CACzC,GAAG,SAAS,MAAM,KAAI,aAAY;GAChC,OAAO,QAAQ;GACf,aAAa,QAAQ;GACrB,MAAM,QAAQ,WAAW,WAAW,oBAAoB;GACxD,OAAO,QAAQ;EACjB,EAAE,GACF,GAAI,SAAS,QACT,CAAC,EAAE,MAAM,YAAqB,GAAG;GAAE,OAAO,EAAE,gBAAgB;GAAG,MAAM;GAAuB,OAAO;GAAQ,UAAU;EAAO,CAAC,IAC7H,CAAC,CACP,CAAC;EAED,MAAM,UAAU,eAAe,YAAY,MAAM,IAAI,CAAC;EACtD,MAAM,WAAW,SAA6B;GAC5C,WAAW,QAAQ,OAAO;GAC1B,MAAM,OAAO;IACX,IAAI,MAAM,OAAO,QAAQ,SAAS,MAAM,GAAG,MAAM,MAAM,QAAQ;GACjE;EACF,CAAC;EAED,SAAS,OAAO,OAAc;GAE5B,MAAM,eAAe;GACrB,KAAK,QAAQ;GACb,SAAS,OAAO,aAAa,IAAI;EACnC;;GAIE,OAAAA,UAAA,GAAAC,YAWEC,MAAA,WAAA,GAAA;IAVS,YAAA,SAAA;IAAA,uBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,SAAQ,QAAA;IACT,MAAM,KAAA;IAAA,iBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,KAAI,QAAA;IACjB,OAAO,MAAA;IACR,aAAU;IACT,MAAM,MAAM;IACZ,gBAAc;IACd,MAAM,QAAA,OAAS,WAAM,SAAA,uBAAA;IACrB,aAAaA,MAAA,CAAA,CAAC,CAACA,MAAA,eAAA,CAAe,CAAC,MAAM,KAAI,CAAE,QAAQ;IACnD,cAAYA,MAAA,CAAA,CAAC,CAAA,qBAAA,EAAA,MAA8BA,MAAA,CAAA,CAAC,CAACA,MAAA,eAAA,CAAe,CAAC,MAAM,KAAI,CAAE,QAAQ,EAAA,CAAA;IACjF,IAAI,EAAA,SAAA,WAAA"}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ModelRole } from "../../../settings/values.js";
|
|
2
2
|
import "../../../settings/index.js";
|
|
3
3
|
import { Editor } from "@tiptap/core";
|
|
4
4
|
//#region src/features/ai/components/ModelQuickSwitch.vue.d.ts
|
|
5
5
|
/**
|
|
6
|
-
* Model profile an AI
|
|
7
|
-
* to every feature of the
|
|
6
|
+
* Model profile an AI Model role runs on. A quick switch *is* the Model role setting (`settings.ai.roles[slot]`): the choice applies
|
|
7
|
+
* to every feature of the Model role, not just to the surrounding dialog. The trailing „Modelle verwalten…“ opens the
|
|
8
8
|
* settings on the „KI“ tab. Inside an editor surface the chrome comes from its provide; mounted beside one, pass its
|
|
9
9
|
* `editor`.
|
|
10
10
|
*/
|
|
11
11
|
type __VLS_Props = {
|
|
12
|
-
slot:
|
|
12
|
+
slot: ModelRole;
|
|
13
13
|
size?: 'xs' | 'sm';
|
|
14
14
|
/** The editor whose settings modal „Modelle verwalten…“ opens, when not mounted inside its editor surface. */
|
|
15
15
|
editor?: Editor;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AI_LANGUAGE_KEYS,
|
|
2
|
-
import { AI_LANGUAGES,
|
|
1
|
+
import { AI_LANGUAGE_KEYS, MODEL_ROLE_KEYS } from "../protocol/models.js";
|
|
2
|
+
import { AI_LANGUAGES, MODEL_ROLES } from "../../../settings/values.js";
|
|
3
3
|
import { useUiKit } from "../../../vue/kit/use-ui-kit.js";
|
|
4
4
|
import { useEditorSettings } from "../../../vue/settings.js";
|
|
5
5
|
import { useEditorI18n } from "../../../vue/use-editor-i18n.js";
|
|
@@ -9,7 +9,7 @@ import _sfc_main$3 from "./SettingsModelProfiles.js";
|
|
|
9
9
|
import { Fragment, createBlock, createElementBlock, createVNode, defineComponent, openBlock, renderList, unref, withCtx } from "vue";
|
|
10
10
|
//#region src/features/ai/components/SettingsAiTab.vue
|
|
11
11
|
const _hoisted_1 = { class: "flex flex-col gap-8" };
|
|
12
|
-
/** „KI“: writing aids, the model profile per
|
|
12
|
+
/** „KI“: writing aids, the model profile per Model role, and model profiles (Model presets and own profiles). */
|
|
13
13
|
const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
14
14
|
__name: "SettingsAiTab",
|
|
15
15
|
setup(__props) {
|
|
@@ -51,16 +51,16 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
51
51
|
_: 1
|
|
52
52
|
}, 8, ["title"]),
|
|
53
53
|
createVNode(_sfc_main$2, {
|
|
54
|
-
title: unref(t)("ai.settings.
|
|
55
|
-
description: unref(t)("ai.settings.
|
|
54
|
+
title: unref(t)("ai.settings.roles.title"),
|
|
55
|
+
description: unref(t)("ai.settings.roles.description")
|
|
56
56
|
}, {
|
|
57
|
-
default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(
|
|
57
|
+
default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(MODEL_ROLES), (slot) => {
|
|
58
58
|
return openBlock(), createBlock(unref(UFormField), {
|
|
59
59
|
key: slot,
|
|
60
60
|
orientation: "horizontal",
|
|
61
61
|
class: "py-3",
|
|
62
|
-
label: unref(t)(unref(
|
|
63
|
-
description: unref(t)(unref(
|
|
62
|
+
label: unref(t)(unref(MODEL_ROLE_KEYS)[slot].labelKey),
|
|
63
|
+
description: unref(t)(unref(MODEL_ROLE_KEYS)[slot].descriptionKey)
|
|
64
64
|
}, {
|
|
65
65
|
default: withCtx(() => [createVNode(_sfc_main$1, {
|
|
66
66
|
slot,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SettingsAiTab.js","names":["_openBlock","_createElementBlock","_createVNode","SettingsSection","_unref","_withCtx","_Fragment","_renderList","_createBlock","ModelQuickSwitch","SettingsModelProfiles"],"sources":["../../../../src/features/ai/components/SettingsAiTab.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport SettingsSection from '../../../vue/components/SettingsSection.vue'\nimport { useUiKit } from '../../../vue/kit/use-ui-kit'\nimport { useEditorSettings } from '../../../vue/settings'\nimport { useEditorI18n } from '../../../vue/use-editor-i18n'\nimport { AI_LANGUAGES,
|
|
1
|
+
{"version":3,"file":"SettingsAiTab.js","names":["_openBlock","_createElementBlock","_createVNode","SettingsSection","_unref","_withCtx","_Fragment","_renderList","_createBlock","ModelQuickSwitch","SettingsModelProfiles"],"sources":["../../../../src/features/ai/components/SettingsAiTab.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport SettingsSection from '../../../vue/components/SettingsSection.vue'\nimport { useUiKit } from '../../../vue/kit/use-ui-kit'\nimport { useEditorSettings } from '../../../vue/settings'\nimport { useEditorI18n } from '../../../vue/use-editor-i18n'\nimport { AI_LANGUAGES, MODEL_ROLES } from '../../../settings'\nimport { AI_LANGUAGE_KEYS, MODEL_ROLE_KEYS } from '../protocol'\nimport ModelQuickSwitch from './ModelQuickSwitch.vue'\nimport SettingsModelProfiles from './SettingsModelProfiles.vue'\n\n/** „KI“: writing aids, the model profile per Model role, and model profiles (Model presets and own profiles). */\nconst { FormField: UFormField, Select: USelect, Switch: USwitch } = useUiKit()\nconst { settings } = useEditorSettings()\nconst { t } = useEditorI18n()\n\nconst languageItems = AI_LANGUAGES.map(l => ({ label: t(AI_LANGUAGE_KEYS[l]), value: l }))\n</script>\n\n<template>\n <div class=\"flex flex-col gap-8\">\n <SettingsSection :title=\"t('ai.settings.writing.title')\">\n <UFormField\n orientation=\"horizontal\"\n class=\"py-3\"\n :label=\"t('ai.settings.autocomplete.label')\"\n :description=\"t('ai.settings.autocomplete.description')\"\n >\n <USwitch v-model=\"settings.ai.autocomplete\" />\n </UFormField>\n <UFormField\n orientation=\"horizontal\"\n class=\"py-3\"\n :label=\"t('ai.settings.language.label')\"\n :description=\"t('ai.settings.language.description')\"\n >\n <USelect v-model=\"settings.ai.translateLanguage\" :items=\"languageItems\" class=\"w-64\" />\n </UFormField>\n </SettingsSection>\n\n <SettingsSection :title=\"t('ai.settings.roles.title')\" :description=\"t('ai.settings.roles.description')\">\n <UFormField\n v-for=\"slot in MODEL_ROLES\"\n :key=\"slot\"\n orientation=\"horizontal\"\n class=\"py-3\"\n :label=\"t(MODEL_ROLE_KEYS[slot].labelKey)\"\n :description=\"t(MODEL_ROLE_KEYS[slot].descriptionKey)\"\n >\n <ModelQuickSwitch :slot=\"slot\" class=\"w-64\" />\n </UFormField>\n </SettingsSection>\n\n <SettingsSection\n :title=\"t('ai.settings.profiles.title')\"\n :description=\"t('ai.settings.profiles.description')\"\n >\n <SettingsModelProfiles />\n </SettingsSection>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;EAWA,MAAM,EAAE,WAAW,YAAY,QAAQ,SAAS,QAAQ,YAAY,SAAS;EAC7E,MAAM,EAAE,aAAa,kBAAkB;EACvC,MAAM,EAAE,MAAM,cAAc;EAE5B,MAAM,gBAAgB,aAAa,KAAI,OAAM;GAAE,OAAO,EAAE,iBAAiB,EAAE;GAAG,OAAO;EAAE,EAAE;;GAIvF,OAAAA,UAAA,GAAAC,mBAuCM,OAvCN,YAuCM;IAtCJC,YAiBkBC,aAAA,EAjBA,OAAOC,MAAA,CAAA,CAAC,CAAA,2BAAA,EAAA,GAAA;KACxB,SAAAC,cAOa,CAPbH,YAOaE,MAAA,UAAA,GAAA;MANX,aAAY;MACZ,OAAM;MACL,OAAOA,MAAA,CAAA,CAAC,CAAA,gCAAA;MACR,aAAaA,MAAA,CAAA,CAAC,CAAA,sCAAA;;MAEf,SAAAC,cAA8C,CAA9CH,YAA8CE,MAAA,OAAA,GAAA;OAA5B,YAAAA,MAAA,QAAA,CAAQ,CAAC,GAAG;OAAZ,uBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,MAAA,QAAA,CAAQ,CAAC,GAAG,eAAY;;;KAE5C,GAAA,GAAA,CAAA,SAAA,aAAA,CAAA,GAAAF,YAOaE,MAAA,UAAA,GAAA;MANX,aAAY;MACZ,OAAM;MACL,OAAOA,MAAA,CAAA,CAAC,CAAA,4BAAA;MACR,aAAaA,MAAA,CAAA,CAAC,CAAA,kCAAA;;MAEf,SAAAC,cAAuF,CAAvFH,YAAuFE,MAAA,OAAA,GAAA;OAArE,YAAAA,MAAA,QAAA,CAAQ,CAAC,GAAG;OAAZ,uBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,MAAA,QAAA,CAAQ,CAAC,GAAG,oBAAiB;OAAG,OAAOA,MAAA,aAAA;OAAe,OAAM;;;;;;IAIlFF,YAWkBC,aAAA;KAXA,OAAOC,MAAA,CAAA,CAAC,CAAA,yBAAA;KAA8B,aAAaA,MAAA,CAAA,CAAC,CAAA,+BAAA;;KAElE,SAAAC,cAA2B,EAD7BL,UAAA,IAAA,GAAAC,mBASaK,UAAA,MAAAC,WARIH,MAAA,WAAA,IAAR,SAAI;MADb,OAAAJ,UAAA,GAAAQ,YASaJ,MAAA,UAAA,GAAA;OAPV,KAAK;OACN,aAAY;OACZ,OAAM;OACL,OAAOA,MAAA,CAAA,CAAC,CAACA,MAAA,eAAA,CAAe,CAAC,KAAI,CAAE,QAAQ;OACvC,aAAaA,MAAA,CAAA,CAAC,CAACA,MAAA,eAAA,CAAe,CAAC,KAAI,CAAE,cAAc;;OAEpD,SAAAC,cAA8C,CAA9CH,YAA8CO,aAAA;QAArB;QAAM,OAAM;;;;;;;IAIzCP,YAKkBC,aAAA;KAJf,OAAOC,MAAA,CAAA,CAAC,CAAA,4BAAA;KACR,aAAaA,MAAA,CAAA,CAAC,CAAA,kCAAA;;KAEf,SAAAC,cAAyB,CAAzBH,YAAyBQ,WAAA,CAAA,CAAA"}
|
|
@@ -33,7 +33,7 @@ const _hoisted_14 = { class: "truncate text-sm font-medium" };
|
|
|
33
33
|
const _hoisted_15 = { class: "truncate text-xs text-[var(--sk-muted)]" };
|
|
34
34
|
const _hoisted_16 = { class: "flex flex-wrap justify-end gap-2" };
|
|
35
35
|
/**
|
|
36
|
-
* Section of the „KI“ tab: the server's presets and this browser's own profiles. Profiles are assigned to
|
|
36
|
+
* Section of the „KI“ tab: the server's Model presets and this browser's own profiles. Profiles are assigned to Model roles in the
|
|
37
37
|
* section above.
|
|
38
38
|
*/
|
|
39
39
|
const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SettingsModelProfiles.js","names":["_openBlock","_createElementBlock","_createElementVNode","_toDisplayString","_unref","_Fragment","_renderList","_createVNode","_createBlock","_createCommentVNode","_withModifiers","_withCtx"],"sources":["../../../../src/features/ai/components/SettingsModelProfiles.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, shallowRef, watch } from 'vue'\nimport { fetchErrorMessage } from '../../../core'\nimport { useEditorContext } from '../../../vue/context'\nimport { useUiKit } from '../../../vue/kit/use-ui-kit'\nimport { useEditorI18n } from '../../../vue/use-editor-i18n'\nimport { modelRefSchema, type UserModelProfile } from '../protocol'\nimport { isRateLimited } from '../rate-limit'\nimport { useModelProfiles } from '../use-model-profiles'\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 */\nconst { Alert: UAlert, Badge: UBadge, Button: UButton, FormField: UFormField, Icon: UIcon, Input: UInput } = useUiKit()\nconst app = useEditorContext()\nconst { presets, userProfiles, saveUserProfile, removeUserProfile } = useModelProfiles()\nconst { t } = useEditorI18n()\n\n/** The profile being added or edited; null while the form is closed. */\nconst draft = ref<UserModelProfile | null>(null)\n/** Result of „Testen“; replaced (not mutated) per run, so a stale run recognizes it was superseded. */\nconst test = shallowRef<{ state: 'running' } | { state: 'ok' } | { state: 'error', message: string } | null>(null)\n\nconst draftRef = computed(() => draft.value && { endpoint: draft.value.endpoint.trim(), model: draft.value.model.trim(), apiKey: draft.value.apiKey.trim() })\nconst draftValid = computed(() => !!draft.value?.label.trim() && modelRefSchema.safeParse(draftRef.value).success)\n// A test result belongs to the values it ran with.\nwatch(draftRef, () => { test.value = null })\n\nfunction edit(profile?: UserModelProfile) {\n draft.value = profile ? { ...profile } : { id: crypto.randomUUID(), label: '', endpoint: '', model: '', apiKey: '' }\n test.value = null\n}\n\nfunction save() {\n if (!draft.value || !draftRef.value || !draftValid.value) return\n saveUserProfile({ id: draft.value.id, label: draft.value.label.trim(), ...draftRef.value })\n draft.value = null\n}\n\nfunction remove(id: string) {\n removeUserProfile(id)\n if (draft.value?.id === id) draft.value = null\n}\n\n/** One short completion through the profile's endpoint (`ai.complete`). */\nasync function runTest() {\n const model = draftRef.value\n if (!model || !draftValid.value) return\n const current = { state: 'running' } as const\n test.value = current\n try {\n if (!app.backend.ai) throw new Error(t('ai.sse.httpError', { status: 501 }))\n await app.backend.ai.complete({ before: 'Hallo', model }, new AbortController().signal)\n if (test.value === current) test.value = { state: 'ok' }\n }\n catch (error) {\n if (test.value === current) test.value = { state: 'error', message: isRateLimited(error) ? t('ai.rateLimited') : fetchErrorMessage(error) }\n }\n}\n</script>\n\n<template>\n <div class=\"flex flex-col divide-y divide-[var(--sk-border)]\">\n <div class=\"py-3 flex flex-col gap-2\">\n <p class=\"text-sm font-medium text-[var(--sk-fg)]\">\n {{ t('ai.profiles.server') }}\n </p>\n <p v-if=\"!presets.length\" class=\"text-sm text-[var(--sk-muted)]\">\n {{ t('ai.profiles.noPresets') }}\n </p>\n <ul v-else class=\"flex flex-col divide-y divide-[var(--sk-border)] rounded-md border border-[var(--sk-border)]\">\n <li v-for=\"preset in presets\" :key=\"preset.id\" class=\"flex items-center gap-3 px-3 py-2\">\n <UIcon name=\"i-lucide-server\" class=\"size-4 shrink-0 text-[var(--sk-muted)]\" />\n <div class=\"min-w-0 flex-1\">\n <p class=\"truncate text-sm font-medium\">\n {{ preset.label }}\n </p>\n <p class=\"truncate text-xs text-[var(--sk-muted)]\">\n {{ preset.model }} · {{ preset.endpoint }}\n </p>\n </div>\n <UBadge :label=\"t('ai.profiles.serverBadge')\" color=\"neutral\" variant=\"subtle\" size=\"sm\" />\n </li>\n </ul>\n </div>\n\n <div class=\"py-3 flex flex-col gap-2\">\n <div class=\"flex items-center justify-between gap-2\">\n <p class=\"text-sm font-medium text-[var(--sk-fg)]\">\n {{ t('ai.profiles.own') }}\n </p>\n <UButton v-if=\"!draft\" :label=\"t('ai.profiles.add')\" icon=\"i-lucide-plus\" size=\"sm\" color=\"neutral\" variant=\"outline\" @click=\"edit()\" />\n </div>\n <ul v-if=\"userProfiles.length\" class=\"flex flex-col divide-y divide-[var(--sk-border)] rounded-md border border-[var(--sk-border)]\">\n <li v-for=\"profile in userProfiles\" :key=\"profile.id\" class=\"flex items-center gap-3 px-3 py-2\">\n <UIcon name=\"i-lucide-key-round\" class=\"size-4 shrink-0 text-[var(--sk-muted)]\" />\n <div class=\"min-w-0 flex-1\">\n <p class=\"truncate text-sm font-medium\">\n {{ profile.label }}\n </p>\n <p class=\"truncate text-xs text-[var(--sk-muted)]\">\n {{ profile.model }} · {{ profile.endpoint }}\n </p>\n </div>\n <UButton icon=\"i-lucide-pencil\" size=\"sm\" color=\"neutral\" variant=\"ghost\" :aria-label=\"t('ai.profiles.edit')\" @click=\"edit(profile)\" />\n <UButton icon=\"i-lucide-trash-2\" size=\"sm\" color=\"error\" variant=\"ghost\" :aria-label=\"t('ai.profiles.delete')\" @click=\"remove(profile.id)\" />\n </li>\n </ul>\n\n <form v-if=\"draft\" class=\"flex flex-col gap-3 rounded-md border border-[var(--sk-border)] p-3\" @submit.prevent=\"save\">\n <UFormField :label=\"t('ai.profiles.name')\" required>\n <UInput v-model=\"draft.label\" :placeholder=\"t('ai.profiles.namePlaceholder')\" class=\"w-full\" />\n </UFormField>\n <UFormField :label=\"t('ai.profiles.endpoint')\" :description=\"t('ai.profiles.endpointHelp')\" required>\n <UInput v-model=\"draft.endpoint\" :placeholder=\"t('ai.profiles.endpointPlaceholder')\" class=\"w-full\" />\n </UFormField>\n <UFormField :label=\"t('ai.profiles.model')\" required>\n <UInput v-model=\"draft.model\" :placeholder=\"t('ai.profiles.modelPlaceholder')\" class=\"w-full\" />\n </UFormField>\n <UFormField :label=\"t('ai.profiles.apiKey')\" required>\n <UInput v-model=\"draft.apiKey\" type=\"password\" autocomplete=\"off\" class=\"w-full\" />\n </UFormField>\n <UAlert v-if=\"test?.state === 'ok'\" color=\"success\" variant=\"subtle\" icon=\"i-lucide-check\" :title=\"t('ai.profiles.testOk')\" />\n <UAlert v-else-if=\"test?.state === 'error'\" color=\"error\" variant=\"subtle\" icon=\"i-lucide-circle-alert\" :title=\"test.message\" />\n <div class=\"flex flex-wrap justify-end gap-2\">\n <UButton\n :label=\"t('ai.profiles.test')\"\n icon=\"i-lucide-plug-zap\"\n color=\"neutral\"\n variant=\"outline\"\n :loading=\"test?.state === 'running'\"\n :disabled=\"!draftValid\"\n @click=\"runTest\"\n />\n <UButton :label=\"t('ai.profiles.cancel')\" color=\"neutral\" variant=\"ghost\" @click=\"draft = null\" />\n <UButton type=\"submit\" :label=\"t('ai.profiles.save')\" :disabled=\"!draftValid\" />\n </div>\n </form>\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcA,MAAM,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,SAAS,WAAW,YAAY,MAAM,OAAO,OAAO,WAAW,SAAS;EACtH,MAAM,MAAM,iBAAiB;EAC7B,MAAM,EAAE,SAAS,cAAc,iBAAiB,sBAAsB,iBAAiB;EACvF,MAAM,EAAE,MAAM,cAAc;;EAG5B,MAAM,QAAQ,IAA6B,IAAI;;EAE/C,MAAM,OAAO,WAAgG,IAAI;EAEjH,MAAM,WAAW,eAAe,MAAM,SAAS;GAAE,UAAU,MAAM,MAAM,SAAS,KAAK;GAAG,OAAO,MAAM,MAAM,MAAM,KAAK;GAAG,QAAQ,MAAM,MAAM,OAAO,KAAK;EAAE,CAAC;EAC5J,MAAM,aAAa,eAAe,CAAC,CAAC,MAAM,OAAO,MAAM,KAAK,KAAK,eAAe,UAAU,SAAS,KAAK,CAAC,CAAC,OAAO;EAEjH,MAAM,gBAAgB;GAAE,KAAK,QAAQ;EAAK,CAAC;EAE3C,SAAS,KAAK,SAA4B;GACxC,MAAM,QAAQ,UAAU,EAAE,GAAG,QAAQ,IAAI;IAAE,IAAI,OAAO,WAAW;IAAG,OAAO;IAAI,UAAU;IAAI,OAAO;IAAI,QAAQ;GAAG;GACnH,KAAK,QAAQ;EACf;EAEA,SAAS,OAAO;GACd,IAAI,CAAC,MAAM,SAAS,CAAC,SAAS,SAAS,CAAC,WAAW,OAAO;GAC1D,gBAAgB;IAAE,IAAI,MAAM,MAAM;IAAI,OAAO,MAAM,MAAM,MAAM,KAAK;IAAG,GAAG,SAAS;GAAM,CAAC;GAC1F,MAAM,QAAQ;EAChB;EAEA,SAAS,OAAO,IAAY;GAC1B,kBAAkB,EAAE;GACpB,IAAI,MAAM,OAAO,OAAO,IAAI,MAAM,QAAQ;EAC5C;;EAGA,eAAe,UAAU;GACvB,MAAM,QAAQ,SAAS;GACvB,IAAI,CAAC,SAAS,CAAC,WAAW,OAAO;GACjC,MAAM,UAAU,EAAE,OAAO,UAAU;GACnC,KAAK,QAAQ;GACb,IAAI;IACF,IAAI,CAAC,IAAI,QAAQ,IAAI,MAAM,IAAI,MAAM,EAAE,oBAAoB,EAAE,QAAQ,IAAI,CAAC,CAAC;IAC3E,MAAM,IAAI,QAAQ,GAAG,SAAS;KAAE,QAAQ;KAAS;IAAM,GAAG,IAAI,gBAAgB,CAAC,CAAC,MAAM;IACtF,IAAI,KAAK,UAAU,SAAS,KAAK,QAAQ,EAAE,OAAO,KAAK;GACzD,SACO,OAAO;IACZ,IAAI,KAAK,UAAU,SAAS,KAAK,QAAQ;KAAE,OAAO;KAAS,SAAS,cAAc,KAAK,IAAI,EAAE,gBAAgB,IAAI,kBAAkB,KAAK;IAAE;GAC5I;EACF;;GAIE,OAAAA,UAAA,GAAAC,mBA6EM,OA7EN,YA6EM,CA5EJC,mBAqBM,OArBN,YAqBM,CApBJA,mBAEI,KAFJ,YAEIC,gBADCC,MAAA,CAAA,CAAC,CAAA,oBAAA,CAAA,GAAA,CAAA,GAEI,CAAAA,MAAA,OAAA,CAAO,CAAC,UAAlBJ,UAAA,GAAAC,mBAEI,KAFJ,YAEIE,gBADCC,MAAA,CAAA,CAAC,CAAA,uBAAA,CAAA,GAAA,CAAA,MAENJ,UAAA,GAAAC,mBAaK,MAbL,YAaK,EAZHD,UAAA,IAAA,GAAAC,mBAWKI,UAAA,MAAAC,WAXgBF,MAAA,OAAA,IAAV,WAAM;IAAjB,OAAAJ,UAAA,GAAAC,mBAWK,MAAA;KAX0B,KAAK,OAAO;KAAI,OAAM;;KACnDM,YAA+EH,MAAA,KAAA,GAAA;MAAxE,MAAK;MAAkB,OAAM;;KACpCF,mBAOM,OAPN,YAOM,CANJA,mBAEI,KAFJ,YAEIC,gBADC,OAAO,KAAK,GAAA,CAAA,GAEjBD,mBAEI,KAFJ,YAEIC,gBADC,OAAO,KAAK,IAAG,QAAGA,gBAAG,OAAO,QAAQ,GAAA,CAAA,CAAA,CAAA;KAG3CI,YAA2FH,MAAA,MAAA,GAAA;MAAlF,OAAOA,MAAA,CAAA,CAAC,CAAA,yBAAA;MAA6B,OAAM;MAAU,SAAQ;MAAS,MAAK;;;GAK1F,CAAA,GAAA,GAAA,EAAA,CAAA,EAAA,CAAA,GAAAF,mBAoDM,OApDN,YAoDM;IAnDJA,mBAKM,OALN,aAKM,CAJJA,mBAEI,KAFJ,aAEIC,gBADCC,MAAA,CAAA,CAAC,CAAA,iBAAA,CAAA,GAAA,CAAA,GAEU,CAAA,MAAA,SAAhBJ,UAAA,GAAAQ,YAAwIJ,MAAA,OAAA,GAAA;;KAAhH,OAAOA,MAAA,CAAA,CAAC,CAAA,iBAAA;KAAqB,MAAK;KAAgB,MAAK;KAAK,OAAM;KAAU,SAAQ;KAAW,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI;;IAE1HA,MAAA,YAAA,CAAY,CAAC,UAAvBJ,UAAA,GAAAC,mBAcK,MAdL,aAcK,EAbHD,UAAA,IAAA,GAAAC,mBAYKI,UAAA,MAAAC,WAZiBF,MAAA,YAAA,IAAX,YAAO;KAAlB,OAAAJ,UAAA,GAAAC,mBAYK,MAAA;MAZgC,KAAK,QAAQ;MAAI,OAAM;;MAC1DM,YAAkFH,MAAA,KAAA,GAAA;OAA3E,MAAK;OAAqB,OAAM;;MACvCF,mBAOM,OAPN,aAOM,CANJA,mBAEI,KAFJ,aAEIC,gBADC,QAAQ,KAAK,GAAA,CAAA,GAElBD,mBAEI,KAFJ,aAEIC,gBADC,QAAQ,KAAK,IAAG,QAAGA,gBAAG,QAAQ,QAAQ,GAAA,CAAA,CAAA,CAAA;MAG7CI,YAAuIH,MAAA,OAAA,GAAA;OAA9H,MAAK;OAAkB,MAAK;OAAK,OAAM;OAAU,SAAQ;OAAS,cAAYA,MAAA,CAAA,CAAC,CAAA,kBAAA;OAAuB,UAAK,WAAE,KAAK,OAAO;;MAClIG,YAA6IH,MAAA,OAAA,GAAA;OAApI,MAAK;OAAmB,MAAK;OAAK,OAAM;OAAQ,SAAQ;OAAS,cAAYA,MAAA,CAAA,CAAC,CAAA,oBAAA;OAAyB,UAAK,WAAE,OAAO,QAAQ,EAAE;;;;IAIhI,MAAA,SAAZJ,UAAA,GAAAC,mBA4BO,QAAA;;KA5BY,OAAM;KAAuE,UAAMS,cAAU,MAAI,CAAA,SAAA,CAAA;;KAClHH,YAEaH,MAAA,UAAA,GAAA;MAFA,OAAOA,MAAA,CAAA,CAAC,CAAA,kBAAA;MAAsB,UAAA;;MACzC,SAAAO,cAA+F,CAA/FJ,YAA+FH,MAAA,MAAA,GAAA;OAA9E,YAAA,MAAA,MAAM;OAAN,uBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,MAAA,MAAM,QAAK;OAAG,aAAaA,MAAA,CAAA,CAAC,CAAA,6BAAA;OAAiC,OAAM;;;;KAEtFG,YAEaH,MAAA,UAAA,GAAA;MAFA,OAAOA,MAAA,CAAA,CAAC,CAAA,sBAAA;MAA2B,aAAaA,MAAA,CAAA,CAAC,CAAA,0BAAA;MAA8B,UAAA;;MAC1F,SAAAO,cAAsG,CAAtGJ,YAAsGH,MAAA,MAAA,GAAA;OAArF,YAAA,MAAA,MAAM;OAAN,uBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,MAAA,MAAM,WAAQ;OAAG,aAAaA,MAAA,CAAA,CAAC,CAAA,iCAAA;OAAqC,OAAM;;;;KAE7FG,YAEaH,MAAA,UAAA,GAAA;MAFA,OAAOA,MAAA,CAAA,CAAC,CAAA,mBAAA;MAAuB,UAAA;;MAC1C,SAAAO,cAAgG,CAAhGJ,YAAgGH,MAAA,MAAA,GAAA;OAA/E,YAAA,MAAA,MAAM;OAAN,uBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,MAAA,MAAM,QAAK;OAAG,aAAaA,MAAA,CAAA,CAAC,CAAA,8BAAA;OAAkC,OAAM;;;;KAEvFG,YAEaH,MAAA,UAAA,GAAA;MAFA,OAAOA,MAAA,CAAA,CAAC,CAAA,oBAAA;MAAwB,UAAA;;MAC3C,SAAAO,cAAmF,CAAnFJ,YAAmFH,MAAA,MAAA,GAAA;OAAlE,YAAA,MAAA,MAAM;OAAN,uBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,MAAA,MAAM,SAAM;OAAE,MAAK;OAAW,cAAa;OAAM,OAAM;;;;KAE5D,KAAA,OAAM,UAAK,QAAzBJ,UAAA,GAAAQ,YAA8HJ,MAAA,MAAA,GAAA;;MAA1F,OAAM;MAAU,SAAQ;MAAS,MAAK;MAAkB,OAAOA,MAAA,CAAA,CAAC,CAAA,oBAAA;KACjF,GAAA,MAAA,GAAA,CAAA,OAAA,CAAA,KAAA,KAAA,OAAM,UAAK,WAA9BJ,UAAA,GAAAQ,YAAgIJ,MAAA,MAAA,GAAA;;MAApF,OAAM;MAAQ,SAAQ;MAAS,MAAK;MAAyB,OAAO,KAAA,MAAK;;KACrHF,mBAYM,OAZN,aAYM;MAXJK,YAQEH,MAAA,OAAA,GAAA;OAPC,OAAOA,MAAA,CAAA,CAAC,CAAA,kBAAA;OACT,MAAK;OACL,OAAM;OACN,SAAQ;OACP,SAAS,KAAA,OAAM,UAAK;OACpB,UAAQ,CAAG,WAAA;OACX,SAAO;;;;;;MAEVG,YAAkGH,MAAA,OAAA,GAAA;OAAxF,OAAOA,MAAA,CAAA,CAAC,CAAA,oBAAA;OAAwB,OAAM;OAAU,SAAQ;OAAS,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,MAAA,QAAK;;MACvFG,YAAgFH,MAAA,OAAA,GAAA;OAAvE,MAAK;OAAU,OAAOA,MAAA,CAAA,CAAC,CAAA,kBAAA;OAAuB,UAAQ,CAAG,WAAA"}
|
|
1
|
+
{"version":3,"file":"SettingsModelProfiles.js","names":["_openBlock","_createElementBlock","_createElementVNode","_toDisplayString","_unref","_Fragment","_renderList","_createVNode","_createBlock","_createCommentVNode","_withModifiers","_withCtx"],"sources":["../../../../src/features/ai/components/SettingsModelProfiles.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, shallowRef, watch } from 'vue'\nimport { fetchErrorMessage } from '../../../core'\nimport { useEditorContext } from '../../../vue/context'\nimport { useUiKit } from '../../../vue/kit/use-ui-kit'\nimport { useEditorI18n } from '../../../vue/use-editor-i18n'\nimport { modelRefSchema, type UserModelProfile } from '../protocol'\nimport { isRateLimited } from '../rate-limit'\nimport { useModelProfiles } from '../use-model-profiles'\n\n/**\n * Section of the „KI“ tab: the server's Model presets and this browser's own profiles. Profiles are assigned to Model roles in the\n * section above.\n */\nconst { Alert: UAlert, Badge: UBadge, Button: UButton, FormField: UFormField, Icon: UIcon, Input: UInput } = useUiKit()\nconst app = useEditorContext()\nconst { presets, userProfiles, saveUserProfile, removeUserProfile } = useModelProfiles()\nconst { t } = useEditorI18n()\n\n/** The profile being added or edited; null while the form is closed. */\nconst draft = ref<UserModelProfile | null>(null)\n/** Result of „Testen“; replaced (not mutated) per run, so a stale run recognizes it was superseded. */\nconst test = shallowRef<{ state: 'running' } | { state: 'ok' } | { state: 'error', message: string } | null>(null)\n\nconst draftRef = computed(() => draft.value && { endpoint: draft.value.endpoint.trim(), model: draft.value.model.trim(), apiKey: draft.value.apiKey.trim() })\nconst draftValid = computed(() => !!draft.value?.label.trim() && modelRefSchema.safeParse(draftRef.value).success)\n// A test result belongs to the values it ran with.\nwatch(draftRef, () => { test.value = null })\n\nfunction edit(profile?: UserModelProfile) {\n draft.value = profile ? { ...profile } : { id: crypto.randomUUID(), label: '', endpoint: '', model: '', apiKey: '' }\n test.value = null\n}\n\nfunction save() {\n if (!draft.value || !draftRef.value || !draftValid.value) return\n saveUserProfile({ id: draft.value.id, label: draft.value.label.trim(), ...draftRef.value })\n draft.value = null\n}\n\nfunction remove(id: string) {\n removeUserProfile(id)\n if (draft.value?.id === id) draft.value = null\n}\n\n/** One short completion through the profile's endpoint (`ai.complete`). */\nasync function runTest() {\n const model = draftRef.value\n if (!model || !draftValid.value) return\n const current = { state: 'running' } as const\n test.value = current\n try {\n if (!app.backend.ai) throw new Error(t('ai.sse.httpError', { status: 501 }))\n await app.backend.ai.complete({ before: 'Hallo', model }, new AbortController().signal)\n if (test.value === current) test.value = { state: 'ok' }\n }\n catch (error) {\n if (test.value === current) test.value = { state: 'error', message: isRateLimited(error) ? t('ai.rateLimited') : fetchErrorMessage(error) }\n }\n}\n</script>\n\n<template>\n <div class=\"flex flex-col divide-y divide-[var(--sk-border)]\">\n <div class=\"py-3 flex flex-col gap-2\">\n <p class=\"text-sm font-medium text-[var(--sk-fg)]\">\n {{ t('ai.profiles.server') }}\n </p>\n <p v-if=\"!presets.length\" class=\"text-sm text-[var(--sk-muted)]\">\n {{ t('ai.profiles.noPresets') }}\n </p>\n <ul v-else class=\"flex flex-col divide-y divide-[var(--sk-border)] rounded-md border border-[var(--sk-border)]\">\n <li v-for=\"preset in presets\" :key=\"preset.id\" class=\"flex items-center gap-3 px-3 py-2\">\n <UIcon name=\"i-lucide-server\" class=\"size-4 shrink-0 text-[var(--sk-muted)]\" />\n <div class=\"min-w-0 flex-1\">\n <p class=\"truncate text-sm font-medium\">\n {{ preset.label }}\n </p>\n <p class=\"truncate text-xs text-[var(--sk-muted)]\">\n {{ preset.model }} · {{ preset.endpoint }}\n </p>\n </div>\n <UBadge :label=\"t('ai.profiles.serverBadge')\" color=\"neutral\" variant=\"subtle\" size=\"sm\" />\n </li>\n </ul>\n </div>\n\n <div class=\"py-3 flex flex-col gap-2\">\n <div class=\"flex items-center justify-between gap-2\">\n <p class=\"text-sm font-medium text-[var(--sk-fg)]\">\n {{ t('ai.profiles.own') }}\n </p>\n <UButton v-if=\"!draft\" :label=\"t('ai.profiles.add')\" icon=\"i-lucide-plus\" size=\"sm\" color=\"neutral\" variant=\"outline\" @click=\"edit()\" />\n </div>\n <ul v-if=\"userProfiles.length\" class=\"flex flex-col divide-y divide-[var(--sk-border)] rounded-md border border-[var(--sk-border)]\">\n <li v-for=\"profile in userProfiles\" :key=\"profile.id\" class=\"flex items-center gap-3 px-3 py-2\">\n <UIcon name=\"i-lucide-key-round\" class=\"size-4 shrink-0 text-[var(--sk-muted)]\" />\n <div class=\"min-w-0 flex-1\">\n <p class=\"truncate text-sm font-medium\">\n {{ profile.label }}\n </p>\n <p class=\"truncate text-xs text-[var(--sk-muted)]\">\n {{ profile.model }} · {{ profile.endpoint }}\n </p>\n </div>\n <UButton icon=\"i-lucide-pencil\" size=\"sm\" color=\"neutral\" variant=\"ghost\" :aria-label=\"t('ai.profiles.edit')\" @click=\"edit(profile)\" />\n <UButton icon=\"i-lucide-trash-2\" size=\"sm\" color=\"error\" variant=\"ghost\" :aria-label=\"t('ai.profiles.delete')\" @click=\"remove(profile.id)\" />\n </li>\n </ul>\n\n <form v-if=\"draft\" class=\"flex flex-col gap-3 rounded-md border border-[var(--sk-border)] p-3\" @submit.prevent=\"save\">\n <UFormField :label=\"t('ai.profiles.name')\" required>\n <UInput v-model=\"draft.label\" :placeholder=\"t('ai.profiles.namePlaceholder')\" class=\"w-full\" />\n </UFormField>\n <UFormField :label=\"t('ai.profiles.endpoint')\" :description=\"t('ai.profiles.endpointHelp')\" required>\n <UInput v-model=\"draft.endpoint\" :placeholder=\"t('ai.profiles.endpointPlaceholder')\" class=\"w-full\" />\n </UFormField>\n <UFormField :label=\"t('ai.profiles.model')\" required>\n <UInput v-model=\"draft.model\" :placeholder=\"t('ai.profiles.modelPlaceholder')\" class=\"w-full\" />\n </UFormField>\n <UFormField :label=\"t('ai.profiles.apiKey')\" required>\n <UInput v-model=\"draft.apiKey\" type=\"password\" autocomplete=\"off\" class=\"w-full\" />\n </UFormField>\n <UAlert v-if=\"test?.state === 'ok'\" color=\"success\" variant=\"subtle\" icon=\"i-lucide-check\" :title=\"t('ai.profiles.testOk')\" />\n <UAlert v-else-if=\"test?.state === 'error'\" color=\"error\" variant=\"subtle\" icon=\"i-lucide-circle-alert\" :title=\"test.message\" />\n <div class=\"flex flex-wrap justify-end gap-2\">\n <UButton\n :label=\"t('ai.profiles.test')\"\n icon=\"i-lucide-plug-zap\"\n color=\"neutral\"\n variant=\"outline\"\n :loading=\"test?.state === 'running'\"\n :disabled=\"!draftValid\"\n @click=\"runTest\"\n />\n <UButton :label=\"t('ai.profiles.cancel')\" color=\"neutral\" variant=\"ghost\" @click=\"draft = null\" />\n <UButton type=\"submit\" :label=\"t('ai.profiles.save')\" :disabled=\"!draftValid\" />\n </div>\n </form>\n </div>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReadonlyStore } from "../../core/store.js";
|
|
2
2
|
import { Translate } from "../../i18n/index.js";
|
|
3
|
-
import {
|
|
3
|
+
import { ModelRole } from "../../settings/values.js";
|
|
4
4
|
import "../../settings/index.js";
|
|
5
5
|
import { EditorBackend } from "../../core/backend.js";
|
|
6
6
|
import { Notifier } from "../../core/notify.js";
|
|
@@ -51,7 +51,7 @@ export interface DocumentChatState {
|
|
|
51
51
|
export interface DocumentChatOptions {
|
|
52
52
|
/** `EditorContext.backend.ai`; without it every question ends in the error state (501), like a server without AI. */
|
|
53
53
|
ai: EditorBackend['ai'];
|
|
54
|
-
modelRef: (slot:
|
|
54
|
+
modelRef: (slot: ModelRole) => ModelRef;
|
|
55
55
|
/** Receives the 429 notice. */
|
|
56
56
|
notify: Notifier;
|
|
57
57
|
/** The app's translator (`EditorContext.t`): error messages, the 429 notice and the snippets of proposed operations. */
|
|
@@ -56,13 +56,13 @@ function createDocumentChat({ ai, modelRef, notify, t }) {
|
|
|
56
56
|
patch({ error: t("ai.chat.emptyScope") });
|
|
57
57
|
return false;
|
|
58
58
|
}
|
|
59
|
-
const {
|
|
59
|
+
const { blockTypes, blocks, structure } = aiContextOf(editor);
|
|
60
60
|
const providers = conversionsOf(editor);
|
|
61
61
|
const targets = [
|
|
62
62
|
...CORE_TARGET_IDS,
|
|
63
|
-
...
|
|
64
|
-
type: "
|
|
65
|
-
|
|
63
|
+
...blockTypes.map((blockType) => convertTargetId({
|
|
64
|
+
type: "typedBlock",
|
|
65
|
+
blockType: blockType.id
|
|
66
66
|
})),
|
|
67
67
|
...blocks.filter((block) => parseConversionTarget(providers, block.id) !== null).map((block) => block.id)
|
|
68
68
|
];
|
|
@@ -105,7 +105,7 @@ function createDocumentChat({ ai, modelRef, notify, t }) {
|
|
|
105
105
|
scope: scope?.ids ?? null,
|
|
106
106
|
nextOp: review.nextOp(),
|
|
107
107
|
model: modelRef("generate"),
|
|
108
|
-
|
|
108
|
+
blockTypes,
|
|
109
109
|
blocks,
|
|
110
110
|
targets,
|
|
111
111
|
structure
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-chat-model.js","names":[],"sources":["../../../src/features/ai/document-chat-model.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { EditorBackend } from '../../core/backend'\nimport { aiContextOf, CORE_TARGET_IDS, convertTargetId, conversionsOf, parseConversionTarget } from '../../core'\nimport { type Notifier, silentNotifier } from '../../core/notify'\nimport { createStore, type ReadonlyStore } from '../../core/store'\nimport type { Translate } from '../../i18n'\nimport type { ModelSlot } from '../../settings'\nimport { type AgentOpReviewState, createAgentOpReview, NO_AGENT_OPS } from './agent-op-review'\nimport type { AgentScope } from './agent-ops'\nimport type { AiTarget } from './ai-apply'\nimport { postAiSse } from './ai-sse'\nimport { documentChatText } from './document-chat'\nimport { type AgentOp, type AgentOpProblem, CHAT_LIMITS, type AiTask, type DocumentChatMessage, type ModelRef } from './protocol'\nimport { notifyAiRateLimited } from './rate-limit'\n\n/**\n * A block generation run from the AI sidebar's quick actions, shown as an assistant turn. Client only: it never goes\n * to the `chat` stream. `markdown` is the streamed result without the task heading (shown with `withTaskHeading`, applied\n * as `taskResultMarkdown`), `target` the apply target captured when it started; only a result that streamed to the end\n * (`done`) can be applied.\n */\nexport interface DocumentChatGeneration {\n task: AiTask\n /** The instruction of a task with `needsPrompt` (empty otherwise). */\n prompt: string\n markdown: string\n target: AiTarget\n done: boolean\n}\n\n/**\n * A chat turn as shown: an assistant turn also keeps the problems of the operations the server dropped, or is a block\n * generation of the sidebar (`generation`).\n */\nexport type DocumentChatTurn =\n | Extract<DocumentChatMessage, { role: 'user' }>\n | (Extract<DocumentChatMessage, { role: 'assistant' }> & { problems?: AgentOpProblem[], generation?: DocumentChatGeneration })\n\n/** Snapshot of a conversation; every change replaces `messages`/`ops` (never mutated in place). */\nexport interface DocumentChatState {\n messages: readonly DocumentChatTurn[]\n /** Operation states by operation id. */\n ops: AgentOpReviewState['ops']\n streaming: boolean\n error: string | null\n}\n\nexport interface DocumentChatOptions {\n /** `EditorContext.backend.ai`; without it every question ends in the error state (501), like a server without AI. */\n ai: EditorBackend['ai']\n modelRef: (slot: ModelSlot) => ModelRef\n /** Receives the 429 notice. */\n notify: Notifier\n /** The app's translator (`EditorContext.t`): error messages, the 429 notice and the snippets of proposed operations. */\n t: Translate\n}\n\nexport interface DocumentChat {\n state: ReadonlyStore<DocumentChatState>\n /**\n * Sends `message` about the editor's current document; `scope` limits proposed edits to the selected blocks (null:\n * whole document). Returns false when it was not answered (error, rate limit, cancelled before any answer): it is\n * then removed again so the caller can restore the input.\n */\n ask: (message: string, editor: Editor, scope: AgentScope | null) => Promise<boolean>\n abort: () => void\n reset: () => void\n /** Accepts or rejects the open hunks of operation `id`. */\n decide: (editor: Editor, id: string, accept: boolean) => void\n /** Scrolls to operation `op`: its first open hunk (selected for accept/reject), else its target block. */\n reveal: (editor: Editor, op: AgentOp) => boolean\n /** Appends the assistant turn of a block generation. `generation` keeps its identity in `state`. */\n addGeneration: (generation: DocumentChatGeneration) => void\n /** Updates `generation` in place (same object) and publishes a new `messages` array. */\n updateGeneration: (generation: DocumentChatGeneration, patch: Partial<Pick<DocumentChatGeneration, 'markdown' | 'done'>>) => void\n /** Removes the turn of `generation`. */\n removeGeneration: (generation: DocumentChatGeneration) => void\n clearError: () => void\n}\n\nconst EMPTY: DocumentChatState = { messages: [], ops: NO_AGENT_OPS, streaming: false, error: null }\n\n/**\n * Document chat state: the conversation lives only here (client side) and goes to the backend's `chat` stream in full with every\n * message, together with the document as it is at that moment and the edit scope. Proposed edit operations open an\n * in-document review; their decisions go to the model with the next message.\n */\nexport function createDocumentChat({ ai, modelRef, notify, t }: DocumentChatOptions): DocumentChat {\n const store = createStore<DocumentChatState>(EMPTY)\n const review = createAgentOpReview({ notify: silentNotifier, t })\n let controller: AbortController | null = null\n\n const patch = (changes: Partial<DocumentChatState>) => store.set({ ...store.get(), ...changes })\n\n function abort() {\n controller?.abort()\n }\n\n function reset() {\n abort()\n controller = null\n store.set(EMPTY)\n review.reset()\n }\n\n /** Replaces the turn `turn` (by identity) with `next`; returns `next`. */\n function replaceTurn<T extends DocumentChatTurn>(turn: DocumentChatTurn, next: T): T {\n const { messages } = store.get()\n const index = messages.indexOf(turn)\n if (index !== -1) patch({ messages: messages.map((m, i) => (i === index ? next : m)) })\n return next\n }\n\n // The proposed operations live in the review (the chat shows their outcomes inline, so it needs no extra notices); its state is the chat's `ops`.\n review.state.subscribe(({ ops }) => {\n if (ops !== store.get().ops) patch({ ops })\n })\n\n async function ask(message: string, editor: Editor, scope: AgentScope | null): Promise<boolean> {\n if (store.get().streaming || !message.trim()) return false\n if (scope && !scope.ids.length) {\n patch({ error: t('ai.chat.emptyScope') })\n return false\n }\n // The block model of the system prompt: the editor's `aiContext` kinds and host blocks, and what `convert` may turn blocks into.\n // Read before any state changes: a merge error in the contributions throws here and must not leave the chat streaming.\n const { kinds, blocks, structure } = aiContextOf(editor)\n const providers = conversionsOf(editor)\n const targets = [\n ...CORE_TARGET_IDS,\n ...kinds.map(kind => convertTargetId({ type: 'composite', kind: kind.id })),\n ...blocks.filter(block => parseConversionTarget(providers, block.id) !== null).map(block => block.id),\n ]\n const own = new AbortController()\n controller = own\n const feedback = review.unreported()\n const userTurn: DocumentChatTurn = { role: 'user', content: message.trim(), ...(feedback.length ? { feedback } : {}) }\n let answer: Extract<DocumentChatTurn, { role: 'assistant' }> = { role: 'assistant', content: '' }\n // The newest chat turns (block generations are the sidebar's own); the request must start with a user message.\n const sent: DocumentChatMessage[] = [...store.get().messages, userTurn].filter(turn => turn.role === 'user' || !turn.generation).slice(-CHAT_LIMITS.messages).map(turn => turn.role === 'user'\n ? { role: 'user', content: turn.content.slice(0, CHAT_LIMITS.message), ...(turn.feedback && { feedback: turn.feedback }) }\n : { role: 'assistant', content: turn.content.slice(0, CHAT_LIMITS.message), ...(turn.ops?.length ? { ops: turn.ops } : {}), ...(turn.dropped ? { dropped: turn.dropped } : {}) })\n if (sent[0]?.role === 'assistant') sent.shift()\n patch({ error: null, streaming: true, messages: [...store.get().messages, userTurn, answer] })\n const received: { proposal?: { ops: AgentOp[], dropped: AgentOpProblem[] } } = {}\n const body = { messages: sent, document: documentChatText(editor), scope: scope?.ids ?? null, nextOp: review.nextOp(), model: modelRef('generate'), kinds, blocks, targets, structure }\n const outcome = await postAiSse(ai, 'chat', body, {\n signal: own.signal,\n t,\n onDelta: (text) => {\n if (controller === own) answer = replaceTurn(answer, { ...answer, content: answer.content + text })\n },\n onEvent: (event, data) => {\n if (event === 'ops' && controller === own) received.proposal = data as typeof received.proposal\n },\n })\n if (controller !== own) return false // superseded by reset()\n controller = null\n patch({ streaming: false })\n const { ops: proposed = [], dropped = [] } = outcome.status === 'done' ? received.proposal ?? {} : {}\n if (outcome.status === 'done' || (outcome.status === 'aborted' && answer.content)) {\n review.markReported(feedback.filter(({ outcome: sentOutcome }) => sentOutcome !== 'pending').map(({ op }) => op))\n if (proposed.length || dropped.length) {\n answer = replaceTurn(answer, { ...answer, ops: proposed, dropped: dropped.length, problems: dropped })\n review.advanceOp(proposed.length)\n if (!editor.isDestroyed) review.propose(editor, proposed, scope)\n }\n return true\n }\n // Drop the unanswered turn: a later message should not carry a dangling one in its history.\n patch({ messages: store.get().messages.slice(0, -2) })\n if (outcome.status === 'rate-limited') notifyAiRateLimited(notify, t)\n else if (outcome.status === 'error') patch({ error: outcome.message })\n return false\n }\n\n const decide = review.decide\n const reveal = review.reveal\n\n function addGeneration(generation: DocumentChatGeneration) {\n patch({ error: null, messages: [...store.get().messages, { role: 'assistant', content: '', generation }] })\n }\n\n function updateGeneration(generation: DocumentChatGeneration, changes: Partial<Pick<DocumentChatGeneration, 'markdown' | 'done'>>) {\n Object.assign(generation, changes)\n const { messages } = store.get()\n patch({ messages: messages.map(turn => turn.role === 'assistant' && turn.generation === generation ? { ...turn } : turn) })\n }\n\n function removeGeneration(generation: DocumentChatGeneration) {\n const { messages } = store.get()\n const index = messages.findIndex(turn => turn.role === 'assistant' && turn.generation === generation)\n if (index !== -1) patch({ messages: messages.filter((_, i) => i !== index) })\n }\n\n function clearError() {\n if (store.get().error !== null) patch({ error: null })\n }\n\n return { state: store, ask, abort, reset, decide, reveal, addGeneration, updateGeneration, removeGeneration, clearError }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"document-chat-model.js","names":[],"sources":["../../../src/features/ai/document-chat-model.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { EditorBackend } from '../../core/backend'\nimport { aiContextOf, CORE_TARGET_IDS, convertTargetId, conversionsOf, parseConversionTarget } from '../../core'\nimport { type Notifier, silentNotifier } from '../../core/notify'\nimport { createStore, type ReadonlyStore } from '../../core/store'\nimport type { Translate } from '../../i18n'\nimport type { ModelRole } from '../../settings'\nimport { type AgentOpReviewState, createAgentOpReview, NO_AGENT_OPS } from './agent-op-review'\nimport type { AgentScope } from './agent-ops'\nimport type { AiTarget } from './ai-apply'\nimport { postAiSse } from './ai-sse'\nimport { documentChatText } from './document-chat'\nimport { type AgentOp, type AgentOpProblem, CHAT_LIMITS, type AiTask, type DocumentChatMessage, type ModelRef } from './protocol'\nimport { notifyAiRateLimited } from './rate-limit'\n\n/**\n * A block generation run from the AI sidebar's quick actions, shown as an assistant turn. Client only: it never goes\n * to the `chat` stream. `markdown` is the streamed result without the task heading (shown with `withTaskHeading`, applied\n * as `taskResultMarkdown`), `target` the apply target captured when it started; only a result that streamed to the end\n * (`done`) can be applied.\n */\nexport interface DocumentChatGeneration {\n task: AiTask\n /** The instruction of a task with `needsPrompt` (empty otherwise). */\n prompt: string\n markdown: string\n target: AiTarget\n done: boolean\n}\n\n/**\n * A chat turn as shown: an assistant turn also keeps the problems of the operations the server dropped, or is a block\n * generation of the sidebar (`generation`).\n */\nexport type DocumentChatTurn =\n | Extract<DocumentChatMessage, { role: 'user' }>\n | (Extract<DocumentChatMessage, { role: 'assistant' }> & { problems?: AgentOpProblem[], generation?: DocumentChatGeneration })\n\n/** Snapshot of a conversation; every change replaces `messages`/`ops` (never mutated in place). */\nexport interface DocumentChatState {\n messages: readonly DocumentChatTurn[]\n /** Operation states by operation id. */\n ops: AgentOpReviewState['ops']\n streaming: boolean\n error: string | null\n}\n\nexport interface DocumentChatOptions {\n /** `EditorContext.backend.ai`; without it every question ends in the error state (501), like a server without AI. */\n ai: EditorBackend['ai']\n modelRef: (slot: ModelRole) => ModelRef\n /** Receives the 429 notice. */\n notify: Notifier\n /** The app's translator (`EditorContext.t`): error messages, the 429 notice and the snippets of proposed operations. */\n t: Translate\n}\n\nexport interface DocumentChat {\n state: ReadonlyStore<DocumentChatState>\n /**\n * Sends `message` about the editor's current document; `scope` limits proposed edits to the selected blocks (null:\n * whole document). Returns false when it was not answered (error, rate limit, cancelled before any answer): it is\n * then removed again so the caller can restore the input.\n */\n ask: (message: string, editor: Editor, scope: AgentScope | null) => Promise<boolean>\n abort: () => void\n reset: () => void\n /** Accepts or rejects the open hunks of operation `id`. */\n decide: (editor: Editor, id: string, accept: boolean) => void\n /** Scrolls to operation `op`: its first open hunk (selected for accept/reject), else its target block. */\n reveal: (editor: Editor, op: AgentOp) => boolean\n /** Appends the assistant turn of a block generation. `generation` keeps its identity in `state`. */\n addGeneration: (generation: DocumentChatGeneration) => void\n /** Updates `generation` in place (same object) and publishes a new `messages` array. */\n updateGeneration: (generation: DocumentChatGeneration, patch: Partial<Pick<DocumentChatGeneration, 'markdown' | 'done'>>) => void\n /** Removes the turn of `generation`. */\n removeGeneration: (generation: DocumentChatGeneration) => void\n clearError: () => void\n}\n\nconst EMPTY: DocumentChatState = { messages: [], ops: NO_AGENT_OPS, streaming: false, error: null }\n\n/**\n * Document chat state: the conversation lives only here (client side) and goes to the backend's `chat` stream in full with every\n * message, together with the document as it is at that moment and the edit scope. Proposed edit operations open an\n * in-document review; their decisions go to the model with the next message.\n */\nexport function createDocumentChat({ ai, modelRef, notify, t }: DocumentChatOptions): DocumentChat {\n const store = createStore<DocumentChatState>(EMPTY)\n const review = createAgentOpReview({ notify: silentNotifier, t })\n let controller: AbortController | null = null\n\n const patch = (changes: Partial<DocumentChatState>) => store.set({ ...store.get(), ...changes })\n\n function abort() {\n controller?.abort()\n }\n\n function reset() {\n abort()\n controller = null\n store.set(EMPTY)\n review.reset()\n }\n\n /** Replaces the turn `turn` (by identity) with `next`; returns `next`. */\n function replaceTurn<T extends DocumentChatTurn>(turn: DocumentChatTurn, next: T): T {\n const { messages } = store.get()\n const index = messages.indexOf(turn)\n if (index !== -1) patch({ messages: messages.map((m, i) => (i === index ? next : m)) })\n return next\n }\n\n // The proposed operations live in the review (the chat shows their outcomes inline, so it needs no extra notices); its state is the chat's `ops`.\n review.state.subscribe(({ ops }) => {\n if (ops !== store.get().ops) patch({ ops })\n })\n\n async function ask(message: string, editor: Editor, scope: AgentScope | null): Promise<boolean> {\n if (store.get().streaming || !message.trim()) return false\n if (scope && !scope.ids.length) {\n patch({ error: t('ai.chat.emptyScope') })\n return false\n }\n // The block model of the system prompt: the editor's `aiContext` Block types and host blocks, and what `convert` may turn blocks into.\n // Read before any state changes: a merge error in the contributions throws here and must not leave the chat streaming.\n const { blockTypes, blocks, structure } = aiContextOf(editor)\n const providers = conversionsOf(editor)\n const targets = [\n ...CORE_TARGET_IDS,\n ...blockTypes.map(blockType => convertTargetId({ type: 'typedBlock', blockType: blockType.id })),\n ...blocks.filter(block => parseConversionTarget(providers, block.id) !== null).map(block => block.id),\n ]\n const own = new AbortController()\n controller = own\n const feedback = review.unreported()\n const userTurn: DocumentChatTurn = { role: 'user', content: message.trim(), ...(feedback.length ? { feedback } : {}) }\n let answer: Extract<DocumentChatTurn, { role: 'assistant' }> = { role: 'assistant', content: '' }\n // The newest chat turns (block generations are the sidebar's own); the request must start with a user message.\n const sent: DocumentChatMessage[] = [...store.get().messages, userTurn].filter(turn => turn.role === 'user' || !turn.generation).slice(-CHAT_LIMITS.messages).map(turn => turn.role === 'user'\n ? { role: 'user', content: turn.content.slice(0, CHAT_LIMITS.message), ...(turn.feedback && { feedback: turn.feedback }) }\n : { role: 'assistant', content: turn.content.slice(0, CHAT_LIMITS.message), ...(turn.ops?.length ? { ops: turn.ops } : {}), ...(turn.dropped ? { dropped: turn.dropped } : {}) })\n if (sent[0]?.role === 'assistant') sent.shift()\n patch({ error: null, streaming: true, messages: [...store.get().messages, userTurn, answer] })\n const received: { proposal?: { ops: AgentOp[], dropped: AgentOpProblem[] } } = {}\n const body = { messages: sent, document: documentChatText(editor), scope: scope?.ids ?? null, nextOp: review.nextOp(), model: modelRef('generate'), blockTypes, blocks, targets, structure }\n const outcome = await postAiSse(ai, 'chat', body, {\n signal: own.signal,\n t,\n onDelta: (text) => {\n if (controller === own) answer = replaceTurn(answer, { ...answer, content: answer.content + text })\n },\n onEvent: (event, data) => {\n if (event === 'ops' && controller === own) received.proposal = data as typeof received.proposal\n },\n })\n if (controller !== own) return false // superseded by reset()\n controller = null\n patch({ streaming: false })\n const { ops: proposed = [], dropped = [] } = outcome.status === 'done' ? received.proposal ?? {} : {}\n if (outcome.status === 'done' || (outcome.status === 'aborted' && answer.content)) {\n review.markReported(feedback.filter(({ outcome: sentOutcome }) => sentOutcome !== 'pending').map(({ op }) => op))\n if (proposed.length || dropped.length) {\n answer = replaceTurn(answer, { ...answer, ops: proposed, dropped: dropped.length, problems: dropped })\n review.advanceOp(proposed.length)\n if (!editor.isDestroyed) review.propose(editor, proposed, scope)\n }\n return true\n }\n // Drop the unanswered turn: a later message should not carry a dangling one in its history.\n patch({ messages: store.get().messages.slice(0, -2) })\n if (outcome.status === 'rate-limited') notifyAiRateLimited(notify, t)\n else if (outcome.status === 'error') patch({ error: outcome.message })\n return false\n }\n\n const decide = review.decide\n const reveal = review.reveal\n\n function addGeneration(generation: DocumentChatGeneration) {\n patch({ error: null, messages: [...store.get().messages, { role: 'assistant', content: '', generation }] })\n }\n\n function updateGeneration(generation: DocumentChatGeneration, changes: Partial<Pick<DocumentChatGeneration, 'markdown' | 'done'>>) {\n Object.assign(generation, changes)\n const { messages } = store.get()\n patch({ messages: messages.map(turn => turn.role === 'assistant' && turn.generation === generation ? { ...turn } : turn) })\n }\n\n function removeGeneration(generation: DocumentChatGeneration) {\n const { messages } = store.get()\n const index = messages.findIndex(turn => turn.role === 'assistant' && turn.generation === generation)\n if (index !== -1) patch({ messages: messages.filter((_, i) => i !== index) })\n }\n\n function clearError() {\n if (store.get().error !== null) patch({ error: null })\n }\n\n return { state: store, ask, abort, reset, decide, reveal, addGeneration, updateGeneration, removeGeneration, clearError }\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { TRUNCATED_LINE, blockLine, compositeChromePart, compositeLineClose, compositeLineHeader, continuedLinePrefix, listLinePrefix, nestedLinePrefix, quoteLinePrefix, singleBlockLine } from "./protocol/block-lines.js";
|
|
2
2
|
import { CHAT_LIMITS, CITATION_HREF_PREFIX, citationBlockId } from "./protocol/chat.js";
|
|
3
|
-
import { parseBlocks } from "../../core/pipeline.js";
|
|
4
3
|
import { blockIdOf, findBlockById } from "../../core/schema/block-ids.js";
|
|
5
4
|
import { isBlockContainer, isChromeNode } from "../../core/schema/node-flags.js";
|
|
5
|
+
import { parseBlocks } from "../../core/pipeline.js";
|
|
6
6
|
import { isWrapperBlock } from "../../core/convert.js";
|
|
7
7
|
import { Fragment } from "@tiptap/pm/model";
|
|
8
8
|
//#region src/features/ai/document-chat.ts
|
|
@@ -44,7 +44,7 @@ function documentChatText(editor) {
|
|
|
44
44
|
node.forEach((child) => {
|
|
45
45
|
if (isChromeNode(child)) chrome.push(compositeChromePart(markdownOf(child)));
|
|
46
46
|
});
|
|
47
|
-
push(blockLine(id, prefix, compositeLineHeader(String(node.attrs.
|
|
47
|
+
push(blockLine(id, prefix, compositeLineHeader(String(node.attrs.blockType), node.attrs.meta, chrome)));
|
|
48
48
|
visit(node, nestedLinePrefix(prefix), id);
|
|
49
49
|
push(compositeLineClose(prefix));
|
|
50
50
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-chat.js","names":[],"sources":["../../../src/features/ai/document-chat.ts"],"sourcesContent":["import type { Editor, JSONContent } from '@tiptap/core'\nimport { Fragment, type Node as PMNode } from '@tiptap/pm/model'\nimport { isWrapperBlock, parseBlocks } from '../../core'\nimport { blockIdOf, findBlockById, isBlockContainer, isChromeNode } from '../../core/schema'\nimport { blockLine, CHAT_LIMITS, CITATION_HREF_PREFIX, citationBlockId, compositeChromePart, compositeLineClose, compositeLineHeader, continuedLinePrefix, listLinePrefix, nestedLinePrefix, quoteLinePrefix, singleBlockLine, TRUNCATED_LINE } from './protocol'\n\n/**\n * The document as sent to the chat, in the line format of `protocol/block-lines.ts` (which also reads and describes\n * it): one line per text block, `[<block id>] <Markdown>` (e.g. `[…] **Anna:** Text`), with list markers and quote\n * prefixes after the ID. Nested blocks carry their own IDs, so quotes from list items or\n * block quotes link to exactly that paragraph. A block container below the document (a composite: the schema flags it\n * `editorBlockContainer`, its title/description/tags rows `editorChrome`) is a header line `[<id>] ::: <kind> {meta} |\n * <title> | <description> | Tags: #a` (empty parts left out), its body blocks two spaces further in, and a closing\n * `:::` line without ID at that indent. Any other non-list block with block content (a host block such as a callout) is\n * a header line `[<id>] <first line of its Markdown form without content>` (`!!! info`) with its body blocks two spaces\n * further in, each with its own ID and no closing line; if that header is empty, only the body blocks appear. Cut at\n * whole lines to fit `CHAT_LIMITS.document`.\n */\nexport function documentChatText(editor: Editor): string {\n const lines: string[] = []\n let size = 0\n let full = false\n\n const push = (line: string) => {\n if (full || size + line.length + 1 > CHAT_LIMITS.document - TRUNCATED_LINE.length - 1) {\n full = true\n return\n }\n lines.push(line)\n size += line.length + 1\n }\n const markdownOf = (node: PMNode) => editor.markdown!.serialize({ type: 'doc', content: [node.toJSON()] }).trim()\n\n const emit = (node: PMNode, prefix: string, id: string | null) => {\n const markdown = markdownOf(node)\n if (!markdown) return\n // Hard breaks and wrapped lines would start new \"blocks\"; code keeps its lines.\n push(blockLine(id, prefix, node.type.name === 'codeBlock' ? markdown : singleBlockLine(markdown)))\n }\n\n const container = (node: PMNode, prefix: string, id: string | null) => {\n const chrome: string[] = []\n // The chrome's own Markdown (`## title`, `> description`, `Tags: #a`) without the block markers.\n node.forEach((child) => {\n if (isChromeNode(child)) chrome.push(compositeChromePart(markdownOf(child)))\n })\n push(blockLine(id, prefix, compositeLineHeader(String(node.attrs.
|
|
1
|
+
{"version":3,"file":"document-chat.js","names":[],"sources":["../../../src/features/ai/document-chat.ts"],"sourcesContent":["import type { Editor, JSONContent } from '@tiptap/core'\nimport { Fragment, type Node as PMNode } from '@tiptap/pm/model'\nimport { isWrapperBlock, parseBlocks } from '../../core'\nimport { blockIdOf, findBlockById, isBlockContainer, isChromeNode } from '../../core/schema'\nimport { blockLine, CHAT_LIMITS, CITATION_HREF_PREFIX, citationBlockId, compositeChromePart, compositeLineClose, compositeLineHeader, continuedLinePrefix, listLinePrefix, nestedLinePrefix, quoteLinePrefix, singleBlockLine, TRUNCATED_LINE } from './protocol'\n\n/**\n * The document as sent to the chat, in the line format of `protocol/block-lines.ts` (which also reads and describes\n * it): one line per text block, `[<block id>] <Markdown>` (e.g. `[…] **Anna:** Text`), with list markers and quote\n * prefixes after the ID. Nested blocks carry their own IDs, so quotes from list items or\n * block quotes link to exactly that paragraph. A block container below the document (a composite: the schema flags it\n * `editorBlockContainer`, its title/description/tags rows `editorChrome`) is a header line `[<id>] ::: <kind> {meta} |\n * <title> | <description> | Tags: #a` (empty parts left out), its body blocks two spaces further in, and a closing\n * `:::` line without ID at that indent. Any other non-list block with block content (a host block such as a callout) is\n * a header line `[<id>] <first line of its Markdown form without content>` (`!!! info`) with its body blocks two spaces\n * further in, each with its own ID and no closing line; if that header is empty, only the body blocks appear. Cut at\n * whole lines to fit `CHAT_LIMITS.document`.\n */\nexport function documentChatText(editor: Editor): string {\n const lines: string[] = []\n let size = 0\n let full = false\n\n const push = (line: string) => {\n if (full || size + line.length + 1 > CHAT_LIMITS.document - TRUNCATED_LINE.length - 1) {\n full = true\n return\n }\n lines.push(line)\n size += line.length + 1\n }\n const markdownOf = (node: PMNode) => editor.markdown!.serialize({ type: 'doc', content: [node.toJSON()] }).trim()\n\n const emit = (node: PMNode, prefix: string, id: string | null) => {\n const markdown = markdownOf(node)\n if (!markdown) return\n // Hard breaks and wrapped lines would start new \"blocks\"; code keeps its lines.\n push(blockLine(id, prefix, node.type.name === 'codeBlock' ? markdown : singleBlockLine(markdown)))\n }\n\n const container = (node: PMNode, prefix: string, id: string | null) => {\n const chrome: string[] = []\n // The chrome's own Markdown (`## title`, `> description`, `Tags: #a`) without the block markers.\n node.forEach((child) => {\n if (isChromeNode(child)) chrome.push(compositeChromePart(markdownOf(child)))\n })\n push(blockLine(id, prefix, compositeLineHeader(String(node.attrs.blockType), node.attrs.meta, chrome)))\n visit(node, nestedLinePrefix(prefix), id)\n push(compositeLineClose(prefix))\n }\n\n // A host block with block content (a callout): its own Markdown form without content as the header line, the body\n // blocks two spaces further in, each with its own ID, no closing line (the form has none).\n const wrapper = (node: PMNode, prefix: string, id: string | null) => {\n const header = markdownOf(node.copy(Fragment.empty)).split('\\n')[0] ?? ''\n if (header) push(blockLine(id, prefix, header))\n visit(node, header ? nestedLinePrefix(prefix) : prefix, id)\n }\n\n const visit = (node: PMNode, prefix: string, parentId: string | null) => {\n let current = prefix\n node.forEach((child, _offset, index) => {\n if (full || isChromeNode(child)) return\n const id = blockIdOf(child) ?? parentId\n if (child.isTextblock || child.isLeaf) emit(child, current, id)\n else if (isBlockContainer(child)) container(child, current, id)\n else if (child.type.name === 'blockquote') visit(child, quoteLinePrefix(current), id)\n else if (child.type.name === 'bulletList' || child.type.name === 'orderedList') {\n const start = Number(child.attrs.start ?? 1)\n child.forEach((item, _o, i) => visit(item, listLinePrefix(current, child.type.name === 'orderedList', start + i), id))\n }\n else if (isWrapperBlock(child)) wrapper(child, current, id)\n else visit(child, current, id)\n // Later blocks of the same list item continue under its marker instead of repeating it.\n if (index === 0) current = continuedLinePrefix(prefix)\n })\n }\n\n visit(editor.state.doc, '', null)\n if (full) lines.push(TRUNCATED_LINE)\n return lines.join('\\n')\n}\n\n/**\n * Chat answer Markdown parsed for display with the pipeline of `editor` (speaker lines become segments where a feature\n * contributes them): quote links whose block exists in `doc` point to `#block-<id>`, and quote links to unknown blocks\n * lose the link (plain text).\n */\nexport function documentChatAnswerContent(editor: Editor, markdown: string, doc: PMNode | undefined): JSONContent {\n const resolve = (node: JSONContent): JSONContent => {\n const marks = node.marks?.flatMap((mark) => {\n if (mark.type !== 'link') return [mark]\n const id = citationBlockId(mark.attrs?.href)\n if (id === null) return [mark]\n return doc && findBlockById(doc, id) ? [{ ...mark, attrs: { ...mark.attrs, href: `${CITATION_HREF_PREFIX}${id}` } }] : []\n })\n return { ...node, ...(marks && { marks }), ...(node.content && { content: node.content.map(resolve) }) }\n }\n return resolve({ type: 'doc', content: parseBlocks(editor, markdown).blocks })\n}\n"],"mappings":"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"}
|
|
@@ -14,9 +14,9 @@ export interface AiUi<C> {
|
|
|
14
14
|
* AI on a core editor: the selection menu and `/ai` (rewrite and generate at the caret), in-document review of
|
|
15
15
|
* rewrites, ghost autocomplete, the model profiles and the `ai` settings tab, the „Mit KI bearbeiten“ block action, the
|
|
16
16
|
* toolbar group (sidebar toggle, autocomplete switch) and Mod-Shift-k. The sidebar (`AiSidebar`) and the model switch
|
|
17
|
-
* are components the host places. Reads the document model through the merged `aiContext` (
|
|
17
|
+
* are components the host places. Reads the document model through the merged `aiContext` (Block types, host blocks,
|
|
18
18
|
* structure) and the `formatAiResult` contribution of other
|
|
19
|
-
* features (defaults: no
|
|
19
|
+
* features (defaults: no Block types, no blocks, flat structure) and maps positions through the preset's anchor resolver, so it imports
|
|
20
20
|
* no composites, transcript, media, mentions, collaboration or Yjs code. The model profiles come from the app context
|
|
21
21
|
* (`modelProfiles(ctx.app)`), shared by all editors of the app.
|
|
22
22
|
*/
|
|
@@ -60,9 +60,9 @@ function aiCommands(ctx) {
|
|
|
60
60
|
* AI on a core editor: the selection menu and `/ai` (rewrite and generate at the caret), in-document review of
|
|
61
61
|
* rewrites, ghost autocomplete, the model profiles and the `ai` settings tab, the „Mit KI bearbeiten“ block action, the
|
|
62
62
|
* toolbar group (sidebar toggle, autocomplete switch) and Mod-Shift-k. The sidebar (`AiSidebar`) and the model switch
|
|
63
|
-
* are components the host places. Reads the document model through the merged `aiContext` (
|
|
63
|
+
* are components the host places. Reads the document model through the merged `aiContext` (Block types, host blocks,
|
|
64
64
|
* structure) and the `formatAiResult` contribution of other
|
|
65
|
-
* features (defaults: no
|
|
65
|
+
* features (defaults: no Block types, no blocks, flat structure) and maps positions through the preset's anchor resolver, so it imports
|
|
66
66
|
* no composites, transcript, media, mentions, collaboration or Yjs code. The model profiles come from the app context
|
|
67
67
|
* (`modelProfiles(ctx.app)`), shared by all editors of the app.
|
|
68
68
|
*/
|