@ecsplico/editor 3.6.0 → 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 +65 -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/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/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 -8
- package/dist/features/composites/merge.js +23 -22
- 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/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 +7 -4
- 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 +6 -6
- 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 -89
- package/dist/features/composites/kinds.js +0 -285
- package/dist/features/composites/kinds.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Store } from "../../core/store.js";
|
|
2
|
-
import {
|
|
2
|
+
import { ModelRole } from "../../settings/values.js";
|
|
3
3
|
import { EditorSettings } from "../../settings/index.js";
|
|
4
4
|
import { EditorBackend } from "../../core/backend.js";
|
|
5
5
|
import { ModelRef } from "../../core/backend-types.js";
|
|
@@ -27,13 +27,13 @@ interface GhostState {
|
|
|
27
27
|
activity: number;
|
|
28
28
|
}
|
|
29
29
|
export declare const ghostAutocompleteKey: PluginKey<GhostState>;
|
|
30
|
-
/** What the suggestion source needs of the app: its AI port and the model profile of a
|
|
30
|
+
/** What the suggestion source needs of the app: its AI port and the model profile of a Model role (`useModelProfiles`). */
|
|
31
31
|
export interface CompletionHost {
|
|
32
32
|
/** `EditorContext.backend.ai`; without it there are no suggestions. */
|
|
33
33
|
ai: EditorBackend['ai'];
|
|
34
|
-
modelRef: (slot:
|
|
34
|
+
modelRef: (slot: ModelRole) => ModelRef;
|
|
35
35
|
}
|
|
36
|
-
/** The suggestion source of the app behind `host`: `ai.complete` on the profile of the `complete`
|
|
36
|
+
/** The suggestion source of the app behind `host`: `ai.complete` on the profile of the `complete` Model role. */
|
|
37
37
|
export declare function completionFetcher(host: CompletionHost): GhostAutocompleteOptions['fetchSuggestion'];
|
|
38
38
|
/**
|
|
39
39
|
* Inline AI autocomplete: after a typing pause at the end of a non-empty textblock, a short continuation is shown as grey
|
|
@@ -28,7 +28,7 @@ function mapSuggestion(suggestion, tr, oldState, newState) {
|
|
|
28
28
|
pos: mapped.pos
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
|
-
/** The suggestion source of the app behind `host`: `ai.complete` on the profile of the `complete`
|
|
31
|
+
/** The suggestion source of the app behind `host`: `ai.complete` on the profile of the `complete` Model role. */
|
|
32
32
|
function completionFetcher(host) {
|
|
33
33
|
return async (before, signal) => {
|
|
34
34
|
if (!host.ai) return "";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ghost-autocomplete.js","names":[],"sources":["../../../src/features/ai/ghost-autocomplete.ts"],"sourcesContent":["import { Extension } from '@tiptap/core'\nimport { type EditorState, Plugin, PluginKey, TextSelection, type Transaction } from '@tiptap/pm/state'\nimport { Decoration, DecorationSet, type EditorView } from '@tiptap/pm/view'\nimport type { Store } from '../../core/store'\nimport { anchorResolverOf, hasAbility } from '../../core'\nimport { ABILITY } from '../../core/schema'\nimport type { EditorSettings, ModelSlot } from '../../settings'\nimport type { EditorBackend } from '../../core/backend'\nimport { AI_COMPLETE_LIMITS, type ModelRef } from './protocol'\n\nexport interface GhostAutocompleteOptions {\n /** The app's shared settings: `ai.autocomplete` switches the suggestions on. */\n settings: Store<EditorSettings>\n /** Pause after the last keystroke before a suggestion is requested (ms). */\n debounce: number\n /** Fetches a continuation of `before` (document text up to the caret); '' for none. Must honour `signal`. */\n fetchSuggestion: (before: string, signal: AbortSignal) => Promise<string>\n}\n\ninterface Suggestion { text: string, pos: number }\ninterface GhostState {\n suggestion: Suggestion | null\n /** Bumped by local edits: each bump starts a new pause, so at most one request follows it. */\n edits: number\n /** Bumped by local edits and caret moves: an in-flight request is stale once this changed. */\n activity: number\n}\ntype GhostMeta = { type: 'show', suggestion: Suggestion } | { type: 'clear' }\n\nexport const ghostAutocompleteKey = new PluginKey<GhostState>('ghostAutocomplete')\n\n/** Text of the caret's textblock, when the caret is an empty selection at the end of a non-empty, non-code textblock. */\nfunction blockTextAtEnd(state: EditorState): string | null {\n const { selection } = state\n if (!(selection instanceof TextSelection) || !selection.empty) return null\n const { $head } = selection\n const block = $head.parent\n if (!block.isTextblock || block.type.spec.code || $head.parentOffset !== block.content.size) return null\n const text = block.textContent\n return text.trim() ? text : null\n}\n\n/** Keeps a suggestion across a collaborator's change only if the caret block is untouched and the caret stayed with it. */\nfunction mapSuggestion(suggestion: Suggestion, tr: Transaction, oldState: EditorState, newState: EditorState): Suggestion | null {\n const mapped = tr.mapping.mapResult(suggestion.pos)\n if (mapped.deleted || newState.selection.head !== mapped.pos) return null\n const text = blockTextAtEnd(newState)\n if (text === null || text !== oldState.doc.resolve(suggestion.pos).parent.textContent) return null\n return { text: suggestion.text, pos: mapped.pos }\n}\n\n/** What the suggestion source needs of the app: its AI port and the model profile of a slot (`useModelProfiles`). */\nexport interface CompletionHost {\n /** `EditorContext.backend.ai`; without it there are no suggestions. */\n ai: EditorBackend['ai']\n modelRef: (slot: ModelSlot) => ModelRef\n}\n\n/** The suggestion source of the app behind `host`: `ai.complete` on the profile of the `complete` slot. */\nexport function completionFetcher(host: CompletionHost): GhostAutocompleteOptions['fetchSuggestion'] {\n return async (before, signal) => {\n if (!host.ai) return ''\n const { text } = await host.ai.complete({ before, model: host.modelRef('complete') }, signal)\n return text\n }\n}\n\n/**\n * Inline AI autocomplete: after a typing pause at the end of a non-empty textblock, a short continuation is shown as grey\n * ghost text after the caret. Tab accepts it as normal text, Esc dismisses it; typing, caret moves and blur clear it.\n * The suggestion is a local widget decoration — never part of the document, so collaborators never see it.\n * On while the editor setting `ai.autocomplete` is (see `useEditorSettings`); turning it off clears the ghost.\n * Client-only: not part of `schemaExtensions()`.\n */\nexport const ghostAutocomplete = (options: GhostAutocompleteOptions) => Extension.create({\n name: 'ghostAutocomplete',\n // Runs its Tab/Escape bindings before ListItem's Tab (sinkListItem); both return false without a suggestion.\n priority: 1000,\n\n addKeyboardShortcuts() {\n return {\n Tab: ({ editor }) => {\n const suggestion = ghostAutocompleteKey.getState(editor.state)?.suggestion\n const { selection } = editor.state\n if (!suggestion || !selection.empty || selection.head !== suggestion.pos) return false\n const end = suggestion.pos + suggestion.text.length\n const tr = editor.state.tr.insertText(suggestion.text, suggestion.pos)\n editor.view.dispatch(tr.setSelection(TextSelection.create(tr.doc, end)).scrollIntoView())\n return true\n },\n Escape: ({ editor }) => {\n if (!ghostAutocompleteKey.getState(editor.state)?.suggestion) return false\n editor.view.dispatch(editor.state.tr.setMeta(ghostAutocompleteKey, { type: 'clear' } satisfies GhostMeta))\n return true\n },\n }\n },\n\n addProseMirrorPlugins() {\n const { editor } = this\n const { settings } = options\n let timer: number | undefined\n let inFlight: AbortController | null = null\n\n function cancel() {\n clearTimeout(timer)\n timer = undefined\n inFlight?.abort()\n inFlight = null\n }\n\n function eligible(view: EditorView): boolean {\n const { state } = view\n if (!settings.get().ai.autocomplete || !editor.isEditable || !view.hasFocus() || view.composing || blockTextAtEnd(state) === null) return false\n if (!hasAbility(editor, ABILITY.aiAutocomplete)) return false\n // No ghost while an @tiptap/suggestion popup (e.g. `@` mentions) is open: its state is `{ active, query, … }`.\n return !state.plugins.some((plugin) => {\n const pluginState: unknown = plugin.getState(state)\n return typeof pluginState === 'object' && pluginState !== null && 'query' in pluginState && 'active' in pluginState && pluginState.active === true\n })\n }\n\n async function request(view: EditorView, activity: number) {\n timer = undefined\n const { state } = view\n if (ghostAutocompleteKey.getState(state)?.activity !== activity || !eligible(view)) return\n const pos = state.selection.head\n const blockText = blockTextAtEnd(state)\n // Positions count at least one per character, so twice the limit in positions covers the character limit.\n const before = state.doc.textBetween(Math.max(0, pos - AI_COMPLETE_LIMITS.before * 2), pos, '\\n\\n').slice(-AI_COMPLETE_LIMITS.before)\n const controller = new AbortController()\n inFlight = controller\n let text: string\n try {\n text = await options.fetchSuggestion(before, controller.signal)\n } catch {\n // Aborted, rate-limited (429) or failed: autocomplete is a silent nicety, so no ghost and no toast.\n return\n } finally {\n if (inFlight === controller) inFlight = null\n }\n if (controller.signal.aborted || !text || view.isDestroyed) return\n // Stale-response guard: no local edit or caret move since the request, and the caret block text is unchanged\n // (a collaborator's change elsewhere may have shifted the caret position).\n const now = view.state\n if (ghostAutocompleteKey.getState(now)?.activity !== activity || !eligible(view) || blockTextAtEnd(now) !== blockText) return\n view.dispatch(now.tr.setMeta(ghostAutocompleteKey, { type: 'show', suggestion: { text, pos: now.selection.head } } satisfies GhostMeta))\n }\n\n return [\n new Plugin<GhostState>({\n key: ghostAutocompleteKey,\n state: {\n init: () => ({ suggestion: null, edits: 0, activity: 0 }),\n apply(tr, prev, oldState, newState) {\n const meta = tr.getMeta(ghostAutocompleteKey) as GhostMeta | undefined\n // A collaborator's edit (the collaboration feature's resolver tells); the user's own undo/redo is not remote.\n const remote = anchorResolverOf(editor)?.isRemoteChange(tr) ?? false\n const edited = tr.docChanged && !remote\n const moved = tr.selectionSet && !remote\n let suggestion = prev.suggestion\n if (meta?.type === 'show') suggestion = meta.suggestion\n else if (meta?.type === 'clear' || edited || moved) suggestion = null\n else if (suggestion && tr.docChanged) suggestion = mapSuggestion(suggestion, tr, oldState, newState)\n if (suggestion === prev.suggestion && !edited && !moved) return prev\n return { suggestion, edits: prev.edits + (edited ? 1 : 0), activity: prev.activity + (edited || moved ? 1 : 0) }\n },\n },\n props: {\n decorations(state) {\n const suggestion = ghostAutocompleteKey.getState(state)?.suggestion\n if (!suggestion) return null\n const widget = Decoration.widget(suggestion.pos, () => {\n const span = document.createElement('span')\n span.className = 'ghost-autocomplete'\n span.contentEditable = 'false'\n span.setAttribute('aria-hidden', 'true')\n span.textContent = suggestion.text\n return span\n }, { side: 1, key: `ghost:${suggestion.text}`, ignoreSelection: true })\n return DecorationSet.create(state.doc, [widget])\n },\n handleDOMEvents: {\n blur(view) {\n cancel()\n if (ghostAutocompleteKey.getState(view.state)?.suggestion) {\n view.dispatch(view.state.tr.setMeta(ghostAutocompleteKey, { type: 'clear' } satisfies GhostMeta))\n }\n return false\n },\n },\n },\n view: (view) => {\n // Turned off (toolbar or settings): drop the pending request and the shown ghost right away.\n let last = settings.get().ai.autocomplete\n const stop = settings.subscribe((value) => {\n const enabled = value.ai.autocomplete\n if (enabled === last) return\n last = enabled\n if (enabled || view.isDestroyed) return\n cancel()\n if (ghostAutocompleteKey.getState(view.state)?.suggestion) {\n view.dispatch(view.state.tr.setMeta(ghostAutocompleteKey, { type: 'clear' } satisfies GhostMeta))\n }\n })\n return {\n update(view, prevState) {\n const next = ghostAutocompleteKey.getState(view.state)\n const prev = ghostAutocompleteKey.getState(prevState)\n if (!next || !prev) return\n if (!settings.get().ai.autocomplete) return cancel()\n if (next.activity === prev.activity) return\n // Typing or a caret move: drop the pending pause and abort the in-flight request.\n cancel()\n // Only a local edit starts a new pause; caret moves alone never request.\n if (next.edits === prev.edits || !eligible(view)) return\n const activity = next.activity\n timer = window.setTimeout(() => void request(view, activity), options.debounce)\n },\n destroy() {\n stop()\n cancel()\n },\n }\n },\n }),\n ]\n },\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ghost-autocomplete.js","names":[],"sources":["../../../src/features/ai/ghost-autocomplete.ts"],"sourcesContent":["import { Extension } from '@tiptap/core'\nimport { type EditorState, Plugin, PluginKey, TextSelection, type Transaction } from '@tiptap/pm/state'\nimport { Decoration, DecorationSet, type EditorView } from '@tiptap/pm/view'\nimport type { Store } from '../../core/store'\nimport { anchorResolverOf, hasAbility } from '../../core'\nimport { ABILITY } from '../../core/schema'\nimport type { EditorSettings, ModelRole } from '../../settings'\nimport type { EditorBackend } from '../../core/backend'\nimport { AI_COMPLETE_LIMITS, type ModelRef } from './protocol'\n\nexport interface GhostAutocompleteOptions {\n /** The app's shared settings: `ai.autocomplete` switches the suggestions on. */\n settings: Store<EditorSettings>\n /** Pause after the last keystroke before a suggestion is requested (ms). */\n debounce: number\n /** Fetches a continuation of `before` (document text up to the caret); '' for none. Must honour `signal`. */\n fetchSuggestion: (before: string, signal: AbortSignal) => Promise<string>\n}\n\ninterface Suggestion { text: string, pos: number }\ninterface GhostState {\n suggestion: Suggestion | null\n /** Bumped by local edits: each bump starts a new pause, so at most one request follows it. */\n edits: number\n /** Bumped by local edits and caret moves: an in-flight request is stale once this changed. */\n activity: number\n}\ntype GhostMeta = { type: 'show', suggestion: Suggestion } | { type: 'clear' }\n\nexport const ghostAutocompleteKey = new PluginKey<GhostState>('ghostAutocomplete')\n\n/** Text of the caret's textblock, when the caret is an empty selection at the end of a non-empty, non-code textblock. */\nfunction blockTextAtEnd(state: EditorState): string | null {\n const { selection } = state\n if (!(selection instanceof TextSelection) || !selection.empty) return null\n const { $head } = selection\n const block = $head.parent\n if (!block.isTextblock || block.type.spec.code || $head.parentOffset !== block.content.size) return null\n const text = block.textContent\n return text.trim() ? text : null\n}\n\n/** Keeps a suggestion across a collaborator's change only if the caret block is untouched and the caret stayed with it. */\nfunction mapSuggestion(suggestion: Suggestion, tr: Transaction, oldState: EditorState, newState: EditorState): Suggestion | null {\n const mapped = tr.mapping.mapResult(suggestion.pos)\n if (mapped.deleted || newState.selection.head !== mapped.pos) return null\n const text = blockTextAtEnd(newState)\n if (text === null || text !== oldState.doc.resolve(suggestion.pos).parent.textContent) return null\n return { text: suggestion.text, pos: mapped.pos }\n}\n\n/** What the suggestion source needs of the app: its AI port and the model profile of a Model role (`useModelProfiles`). */\nexport interface CompletionHost {\n /** `EditorContext.backend.ai`; without it there are no suggestions. */\n ai: EditorBackend['ai']\n modelRef: (slot: ModelRole) => ModelRef\n}\n\n/** The suggestion source of the app behind `host`: `ai.complete` on the profile of the `complete` Model role. */\nexport function completionFetcher(host: CompletionHost): GhostAutocompleteOptions['fetchSuggestion'] {\n return async (before, signal) => {\n if (!host.ai) return ''\n const { text } = await host.ai.complete({ before, model: host.modelRef('complete') }, signal)\n return text\n }\n}\n\n/**\n * Inline AI autocomplete: after a typing pause at the end of a non-empty textblock, a short continuation is shown as grey\n * ghost text after the caret. Tab accepts it as normal text, Esc dismisses it; typing, caret moves and blur clear it.\n * The suggestion is a local widget decoration — never part of the document, so collaborators never see it.\n * On while the editor setting `ai.autocomplete` is (see `useEditorSettings`); turning it off clears the ghost.\n * Client-only: not part of `schemaExtensions()`.\n */\nexport const ghostAutocomplete = (options: GhostAutocompleteOptions) => Extension.create({\n name: 'ghostAutocomplete',\n // Runs its Tab/Escape bindings before ListItem's Tab (sinkListItem); both return false without a suggestion.\n priority: 1000,\n\n addKeyboardShortcuts() {\n return {\n Tab: ({ editor }) => {\n const suggestion = ghostAutocompleteKey.getState(editor.state)?.suggestion\n const { selection } = editor.state\n if (!suggestion || !selection.empty || selection.head !== suggestion.pos) return false\n const end = suggestion.pos + suggestion.text.length\n const tr = editor.state.tr.insertText(suggestion.text, suggestion.pos)\n editor.view.dispatch(tr.setSelection(TextSelection.create(tr.doc, end)).scrollIntoView())\n return true\n },\n Escape: ({ editor }) => {\n if (!ghostAutocompleteKey.getState(editor.state)?.suggestion) return false\n editor.view.dispatch(editor.state.tr.setMeta(ghostAutocompleteKey, { type: 'clear' } satisfies GhostMeta))\n return true\n },\n }\n },\n\n addProseMirrorPlugins() {\n const { editor } = this\n const { settings } = options\n let timer: number | undefined\n let inFlight: AbortController | null = null\n\n function cancel() {\n clearTimeout(timer)\n timer = undefined\n inFlight?.abort()\n inFlight = null\n }\n\n function eligible(view: EditorView): boolean {\n const { state } = view\n if (!settings.get().ai.autocomplete || !editor.isEditable || !view.hasFocus() || view.composing || blockTextAtEnd(state) === null) return false\n if (!hasAbility(editor, ABILITY.aiAutocomplete)) return false\n // No ghost while an @tiptap/suggestion popup (e.g. `@` mentions) is open: its state is `{ active, query, … }`.\n return !state.plugins.some((plugin) => {\n const pluginState: unknown = plugin.getState(state)\n return typeof pluginState === 'object' && pluginState !== null && 'query' in pluginState && 'active' in pluginState && pluginState.active === true\n })\n }\n\n async function request(view: EditorView, activity: number) {\n timer = undefined\n const { state } = view\n if (ghostAutocompleteKey.getState(state)?.activity !== activity || !eligible(view)) return\n const pos = state.selection.head\n const blockText = blockTextAtEnd(state)\n // Positions count at least one per character, so twice the limit in positions covers the character limit.\n const before = state.doc.textBetween(Math.max(0, pos - AI_COMPLETE_LIMITS.before * 2), pos, '\\n\\n').slice(-AI_COMPLETE_LIMITS.before)\n const controller = new AbortController()\n inFlight = controller\n let text: string\n try {\n text = await options.fetchSuggestion(before, controller.signal)\n } catch {\n // Aborted, rate-limited (429) or failed: autocomplete is a silent nicety, so no ghost and no toast.\n return\n } finally {\n if (inFlight === controller) inFlight = null\n }\n if (controller.signal.aborted || !text || view.isDestroyed) return\n // Stale-response guard: no local edit or caret move since the request, and the caret block text is unchanged\n // (a collaborator's change elsewhere may have shifted the caret position).\n const now = view.state\n if (ghostAutocompleteKey.getState(now)?.activity !== activity || !eligible(view) || blockTextAtEnd(now) !== blockText) return\n view.dispatch(now.tr.setMeta(ghostAutocompleteKey, { type: 'show', suggestion: { text, pos: now.selection.head } } satisfies GhostMeta))\n }\n\n return [\n new Plugin<GhostState>({\n key: ghostAutocompleteKey,\n state: {\n init: () => ({ suggestion: null, edits: 0, activity: 0 }),\n apply(tr, prev, oldState, newState) {\n const meta = tr.getMeta(ghostAutocompleteKey) as GhostMeta | undefined\n // A collaborator's edit (the collaboration feature's resolver tells); the user's own undo/redo is not remote.\n const remote = anchorResolverOf(editor)?.isRemoteChange(tr) ?? false\n const edited = tr.docChanged && !remote\n const moved = tr.selectionSet && !remote\n let suggestion = prev.suggestion\n if (meta?.type === 'show') suggestion = meta.suggestion\n else if (meta?.type === 'clear' || edited || moved) suggestion = null\n else if (suggestion && tr.docChanged) suggestion = mapSuggestion(suggestion, tr, oldState, newState)\n if (suggestion === prev.suggestion && !edited && !moved) return prev\n return { suggestion, edits: prev.edits + (edited ? 1 : 0), activity: prev.activity + (edited || moved ? 1 : 0) }\n },\n },\n props: {\n decorations(state) {\n const suggestion = ghostAutocompleteKey.getState(state)?.suggestion\n if (!suggestion) return null\n const widget = Decoration.widget(suggestion.pos, () => {\n const span = document.createElement('span')\n span.className = 'ghost-autocomplete'\n span.contentEditable = 'false'\n span.setAttribute('aria-hidden', 'true')\n span.textContent = suggestion.text\n return span\n }, { side: 1, key: `ghost:${suggestion.text}`, ignoreSelection: true })\n return DecorationSet.create(state.doc, [widget])\n },\n handleDOMEvents: {\n blur(view) {\n cancel()\n if (ghostAutocompleteKey.getState(view.state)?.suggestion) {\n view.dispatch(view.state.tr.setMeta(ghostAutocompleteKey, { type: 'clear' } satisfies GhostMeta))\n }\n return false\n },\n },\n },\n view: (view) => {\n // Turned off (toolbar or settings): drop the pending request and the shown ghost right away.\n let last = settings.get().ai.autocomplete\n const stop = settings.subscribe((value) => {\n const enabled = value.ai.autocomplete\n if (enabled === last) return\n last = enabled\n if (enabled || view.isDestroyed) return\n cancel()\n if (ghostAutocompleteKey.getState(view.state)?.suggestion) {\n view.dispatch(view.state.tr.setMeta(ghostAutocompleteKey, { type: 'clear' } satisfies GhostMeta))\n }\n })\n return {\n update(view, prevState) {\n const next = ghostAutocompleteKey.getState(view.state)\n const prev = ghostAutocompleteKey.getState(prevState)\n if (!next || !prev) return\n if (!settings.get().ai.autocomplete) return cancel()\n if (next.activity === prev.activity) return\n // Typing or a caret move: drop the pending pause and abort the in-flight request.\n cancel()\n // Only a local edit starts a new pause; caret moves alone never request.\n if (next.edits === prev.edits || !eligible(view)) return\n const activity = next.activity\n timer = window.setTimeout(() => void request(view, activity), options.debounce)\n },\n destroy() {\n stop()\n cancel()\n },\n }\n },\n }),\n ]\n },\n})\n"],"mappings":"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"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { ModelProfile, ModelRef } from "../../core/backend-types.js";
|
|
2
2
|
import { BLOCK_LINES_LABEL, BLOCK_LINE_COMPOSITE_TEXT, BLOCK_LINE_ECHO_TEXT, BLOCK_LINE_EXAMPLE, BLOCK_LINE_EXAMPLE_ID, BLOCK_LINE_EXAMPLE_TEXT, BLOCK_LINE_HOST_TEXT, BLOCK_LINE_IDS_HINT, BLOCK_LINE_INTRO, BLOCK_LINE_LIST_TEXT, BLOCK_LINE_MARKERS, BlockLines, TRUNCATED_LINE, blockLine, compositeChromePart, compositeLineClose, compositeLineHeader, continuedLinePrefix, listLinePrefix, nestedLinePrefix, quoteLinePrefix, readBlockLines, singleBlockLine, stripBlockLineEcho, stripListMarkerEcho } from "./protocol/block-lines.js";
|
|
3
3
|
import { AGENT_LIMITS, AGENT_OP_OUTCOMES, AGENT_OP_OUTCOME_TEXT, AGENT_OP_TYPES, AGENT_TOOL, AgentOp, AgentOpContext, AgentOpFeedback, AgentOpOutcome, AgentOpProblem, AgentOpProblemReason, AgentOpType, AgentTextOptions, ModelAgentOp, agentFeedbackText, agentOpSummary, agentOpTarget, agentRetryMessage, agentShownMessage, agentUnreadableProblem, checkAgentOps } from "./protocol/agent-ops.js";
|
|
4
|
-
import { CHAT_LIMITS, CITATION_HREF_PREFIX, ChatBlock, ChatBlockModel,
|
|
4
|
+
import { CHAT_LIMITS, CITATION_HREF_PREFIX, ChatBlock, ChatBlockModel, ChatBlockType, DocumentChatMessage, citationBlockId, documentChatMessages } from "./protocol/chat.js";
|
|
5
5
|
import { AI_LIMITS, AI_TASKS, AI_TASK_IDS, AiApplyMode, AiBlockInput, AiInput, AiMessage, AiTask, AiTaskId, blockTasks, inBlockTasks, withHeading, withTaskHeading } from "./protocol/tasks.js";
|
|
6
6
|
import { ChatMessage, ChatStream, GenerateInput, generateBodySchema, generateProblem, runGenerate } from "./protocol/generate.js";
|
|
7
7
|
import { AI_COMPLETE_LIMITS, AiCompleteMessage, cleanCompletion, completeBodySchema, completeMessages, completionReady, runCompletion } from "./protocol/complete.js";
|
|
8
|
-
import { AI_LANGUAGE_KEYS, MODEL_REF_LIMITS,
|
|
8
|
+
import { AI_LANGUAGE_KEYS, MODEL_REF_LIMITS, MODEL_ROLE_KEYS, UserModelProfile, modelRefSchema } from "./protocol/models.js";
|
|
9
9
|
import { AI_ID_PATTERN, aiBlockInputSchema, aiBlockSchema } from "./protocol/schemas.js";
|
|
10
10
|
import "./protocol/index.js";
|
|
11
11
|
import { AiReview, AiReviewChange, AiReviewChangeSummary, AiReviewDecision, AiReviewHandle, AiReviewHunk, AiReviewOptions, AiReviewOutcome, AiReviewSkipReason, AiReviewState, acceptAiReview, aiReviewKey, rejectAiReview, setActiveAiReviewHunk, startAiReview } from "./ai-review.js";
|
|
@@ -25,4 +25,4 @@ import { ModelProfilesModel, modelProfiles } from "./model-profiles.js";
|
|
|
25
25
|
import { isRateLimited, notifyAiRateLimited } from "./rate-limit.js";
|
|
26
26
|
import { AiSidebarFlow, AiSidebarFlowOptions, createAiSidebarFlow } from "./sidebar-flow.js";
|
|
27
27
|
import { AI_SELECTION_MENU_KEY, AiSelectionFlow, AiSelectionFlowOptions, AiSelectionMode, AiSelectionRequest, AiSelectionState, createAiSelectionFlow } from "./selection-flow.js";
|
|
28
|
-
export { AGENT_LIMITS, AGENT_OP_OUTCOMES, AGENT_OP_OUTCOME_TEXT, AGENT_OP_TYPES, AGENT_TOOL, AI_COMPLETE_LIMITS, AI_ID_PATTERN, AI_LANGUAGE_KEYS, AI_LIMITS, AI_MENU_AT_CARET, AI_MENU_FOR_SELECTION, AI_SELECTION_MENU_KEY, AI_TASKS, AI_TASK_IDS, AgentOp, AgentOpContext, AgentOpFeedback, AgentOpOutcome, AgentOpProblem, AgentOpProblemReason, type AgentOpReview, type AgentOpReviewOptions, type AgentOpReviewState, type AgentOpState, AgentOpType, type AgentScope, AgentTextOptions, AiApplyMode, type AiApplyOutcome, type AiAssistant, type AiAssistantOptions, type AiAssistantState, AiBlockInput, AiCompleteMessage, AiInput, type AiMenuAction, AiMessage, type AiResultAction, AiReview, type AiReviewChange, type AiReviewChangeSummary, type AiReviewDecision, type AiReviewHandle, type AiReviewHunk, type AiReviewOptions, type AiReviewOutcome, type AiReviewSkipReason, type AiReviewState, type AiRunBody, type AiSelectionFlow, type AiSelectionFlowOptions, AiSelectionHighlight, type AiSelectionMode, type AiSelectionRequest, type AiSelectionState, type AiSidebarFlow, type AiSidebarFlowOptions, type AiSseOutcome, type AiStatus, type AiTarget, AiTask, AiTaskId, type AiUi, BLOCK_LINES_LABEL, BLOCK_LINE_COMPOSITE_TEXT, BLOCK_LINE_ECHO_TEXT, BLOCK_LINE_EXAMPLE, BLOCK_LINE_EXAMPLE_ID, BLOCK_LINE_EXAMPLE_TEXT, BLOCK_LINE_HOST_TEXT, BLOCK_LINE_IDS_HINT, BLOCK_LINE_INTRO, BLOCK_LINE_LIST_TEXT, BLOCK_LINE_MARKERS, BlockLines, CHAT_LIMITS, CITATION_HREF_PREFIX, ChatBlock, ChatBlockModel,
|
|
28
|
+
export { AGENT_LIMITS, AGENT_OP_OUTCOMES, AGENT_OP_OUTCOME_TEXT, AGENT_OP_TYPES, AGENT_TOOL, AI_COMPLETE_LIMITS, AI_ID_PATTERN, AI_LANGUAGE_KEYS, AI_LIMITS, AI_MENU_AT_CARET, AI_MENU_FOR_SELECTION, AI_SELECTION_MENU_KEY, AI_TASKS, AI_TASK_IDS, AgentOp, AgentOpContext, AgentOpFeedback, AgentOpOutcome, AgentOpProblem, AgentOpProblemReason, type AgentOpReview, type AgentOpReviewOptions, type AgentOpReviewState, type AgentOpState, AgentOpType, type AgentScope, AgentTextOptions, AiApplyMode, type AiApplyOutcome, type AiAssistant, type AiAssistantOptions, type AiAssistantState, AiBlockInput, AiCompleteMessage, AiInput, type AiMenuAction, AiMessage, type AiResultAction, AiReview, type AiReviewChange, type AiReviewChangeSummary, type AiReviewDecision, type AiReviewHandle, type AiReviewHunk, type AiReviewOptions, type AiReviewOutcome, type AiReviewSkipReason, type AiReviewState, type AiRunBody, type AiSelectionFlow, type AiSelectionFlowOptions, AiSelectionHighlight, type AiSelectionMode, type AiSelectionRequest, type AiSelectionState, type AiSidebarFlow, type AiSidebarFlowOptions, type AiSseOutcome, type AiStatus, type AiTarget, AiTask, AiTaskId, type AiUi, BLOCK_LINES_LABEL, BLOCK_LINE_COMPOSITE_TEXT, BLOCK_LINE_ECHO_TEXT, BLOCK_LINE_EXAMPLE, BLOCK_LINE_EXAMPLE_ID, BLOCK_LINE_EXAMPLE_TEXT, BLOCK_LINE_HOST_TEXT, BLOCK_LINE_IDS_HINT, BLOCK_LINE_INTRO, BLOCK_LINE_LIST_TEXT, BLOCK_LINE_MARKERS, BlockLines, CHAT_LIMITS, CITATION_HREF_PREFIX, ChatBlock, ChatBlockModel, ChatBlockType, ChatMessage, ChatStream, type DocumentChat, type DocumentChatGeneration, DocumentChatMessage, type DocumentChatOptions, type DocumentChatState, type DocumentChatTurn, GenerateInput, type GhostAutocompleteOptions, MODEL_REF_LIMITS, MODEL_ROLE_KEYS, ModelAgentOp, type ModelProfile, type ModelProfilesModel, type ModelRef, TRUNCATED_LINE, UserModelProfile, acceptAiReview, agentFeedbackText, agentOpSummary, agentOpTarget, agentRetryMessage, agentShownMessage, agentUnreadableProblem, aiApplyFailure, aiBlockAction, aiBlockInputSchema, aiBlockSchema, aiCommand, aiFeatureCore, aiMenuActionsOf, aiReviewKey, aiSelectionHighlightKey, applyAiResult, blockLine, blockTasks, blockTextRange, captureTarget, checkAgentOps, citationBlockId, cleanCompletion, completeBodySchema, completeMessages, completionFetcher, completionReady, compositeChromePart, compositeLineClose, compositeLineHeader, continuedLinePrefix, createAgentOpReview, createAiAssistant, createAiSelectionFlow, createAiSidebarFlow, createDocumentChat, documentChatMessages, documentChatText, documentMarkdown, formatTaskResult, generateBodySchema, generateProblem, ghostAutocomplete, ghostAutocompleteKey, hideAiSelectionHighlight, inBlockTasks, insertAtCaretLine, insertBlocksAtTarget, insertBlocksBelow, isRateLimited, listLinePrefix, modelProfiles, modelRefSchema, nestedLinePrefix, notifyAiRateLimited, openAiMenuAtCaret, openAiMenuForSelection, postAiSse, quoteLinePrefix, rangeMarkdown, readBlockLines, rejectAiReview, resultBlocks, runCompletion, runGenerate, selectionMarkdown, selectionScope, setActiveAiReviewHunk, showAiSelectionHighlight, singleBlockLine, startAiReview, stripBlockLineEcho, stripListMarkerEcho, withHeading, withTaskHeading };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AI_LANGUAGE_KEYS, MODEL_REF_LIMITS,
|
|
1
|
+
import { AI_LANGUAGE_KEYS, MODEL_REF_LIMITS, MODEL_ROLE_KEYS, modelRefSchema } from "./protocol/models.js";
|
|
2
2
|
import { AI_COMPLETE_LIMITS, cleanCompletion, completeBodySchema, completeMessages, completionReady, runCompletion } from "./protocol/complete.js";
|
|
3
3
|
import { AI_LIMITS, AI_TASKS, AI_TASK_IDS, blockTasks, inBlockTasks, withHeading, withTaskHeading } from "./protocol/tasks.js";
|
|
4
4
|
import { AI_ID_PATTERN, aiBlockInputSchema, aiBlockSchema } from "./protocol/schemas.js";
|
|
@@ -23,4 +23,4 @@ import { createAiSidebarFlow } from "./sidebar-flow.js";
|
|
|
23
23
|
import { documentChatText } from "./document-chat.js";
|
|
24
24
|
import { createAgentOpReview } from "./agent-op-review.js";
|
|
25
25
|
import { createDocumentChat } from "./document-chat-model.js";
|
|
26
|
-
export { AGENT_LIMITS, AGENT_OP_OUTCOMES, AGENT_OP_OUTCOME_TEXT, AGENT_OP_TYPES, AGENT_TOOL, AI_COMPLETE_LIMITS, AI_ID_PATTERN, AI_LANGUAGE_KEYS, AI_LIMITS, AI_MENU_AT_CARET, AI_MENU_FOR_SELECTION, AI_SELECTION_MENU_KEY, AI_TASKS, AI_TASK_IDS, AiReview, AiSelectionHighlight, BLOCK_LINES_LABEL, BLOCK_LINE_COMPOSITE_TEXT, BLOCK_LINE_ECHO_TEXT, BLOCK_LINE_EXAMPLE, BLOCK_LINE_EXAMPLE_ID, BLOCK_LINE_EXAMPLE_TEXT, BLOCK_LINE_HOST_TEXT, BLOCK_LINE_IDS_HINT, BLOCK_LINE_INTRO, BLOCK_LINE_LIST_TEXT, BLOCK_LINE_MARKERS, CHAT_LIMITS, CITATION_HREF_PREFIX, MODEL_REF_LIMITS,
|
|
26
|
+
export { AGENT_LIMITS, AGENT_OP_OUTCOMES, AGENT_OP_OUTCOME_TEXT, AGENT_OP_TYPES, AGENT_TOOL, AI_COMPLETE_LIMITS, AI_ID_PATTERN, AI_LANGUAGE_KEYS, AI_LIMITS, AI_MENU_AT_CARET, AI_MENU_FOR_SELECTION, AI_SELECTION_MENU_KEY, AI_TASKS, AI_TASK_IDS, AiReview, AiSelectionHighlight, BLOCK_LINES_LABEL, BLOCK_LINE_COMPOSITE_TEXT, BLOCK_LINE_ECHO_TEXT, BLOCK_LINE_EXAMPLE, BLOCK_LINE_EXAMPLE_ID, BLOCK_LINE_EXAMPLE_TEXT, BLOCK_LINE_HOST_TEXT, BLOCK_LINE_IDS_HINT, BLOCK_LINE_INTRO, BLOCK_LINE_LIST_TEXT, BLOCK_LINE_MARKERS, CHAT_LIMITS, CITATION_HREF_PREFIX, MODEL_REF_LIMITS, MODEL_ROLE_KEYS, TRUNCATED_LINE, acceptAiReview, agentFeedbackText, agentOpSummary, agentOpTarget, agentRetryMessage, agentShownMessage, agentUnreadableProblem, aiApplyFailure, aiBlockAction, aiBlockInputSchema, aiBlockSchema, aiCommand, aiFeatureCore, aiMenuActionsOf, aiReviewKey, aiSelectionHighlightKey, applyAiResult, blockLine, blockTasks, blockTextRange, captureTarget, checkAgentOps, citationBlockId, cleanCompletion, completeBodySchema, completeMessages, completionFetcher, completionReady, compositeChromePart, compositeLineClose, compositeLineHeader, continuedLinePrefix, createAgentOpReview, createAiAssistant, createAiSelectionFlow, createAiSidebarFlow, createDocumentChat, documentChatMessages, documentChatText, documentMarkdown, formatTaskResult, generateBodySchema, generateProblem, ghostAutocomplete, ghostAutocompleteKey, hideAiSelectionHighlight, inBlockTasks, insertAtCaretLine, insertBlocksAtTarget, insertBlocksBelow, isRateLimited, listLinePrefix, modelProfiles, modelRefSchema, nestedLinePrefix, notifyAiRateLimited, openAiMenuAtCaret, openAiMenuForSelection, postAiSse, quoteLinePrefix, rangeMarkdown, readBlockLines, rejectAiReview, resultBlocks, runCompletion, runGenerate, selectionMarkdown, selectionScope, setActiveAiReviewHunk, showAiSelectionHighlight, singleBlockLine, startAiReview, stripBlockLineEcho, stripListMarkerEcho, withHeading, withTaskHeading };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReadonlyStore, Store } from "../../core/store.js";
|
|
2
|
-
import {
|
|
2
|
+
import { ModelRole } from "../../settings/values.js";
|
|
3
3
|
import "../../settings/index.js";
|
|
4
4
|
import { EditorContext } from "../../core/context.js";
|
|
5
5
|
import { ModelProfile, ModelRef } from "../../core/backend-types.js";
|
|
@@ -15,22 +15,22 @@ export interface ModelProfilesModel {
|
|
|
15
15
|
/** Presets, then user profiles. Reads the stores: call it again after either changed. */
|
|
16
16
|
profiles: () => ModelProfile[];
|
|
17
17
|
/**
|
|
18
|
-
* Profile a
|
|
19
|
-
* first preset; none before the presets loaded (unless the settings point at a user profile).
|
|
18
|
+
* Profile a Model role runs on: the one the settings assign to it, else the server's default Model preset for the Model role, else the
|
|
19
|
+
* first Model preset; none before the Model presets loaded (unless the settings point at a user profile).
|
|
20
20
|
*/
|
|
21
|
-
slotProfile: (slot:
|
|
22
|
-
/** What AI requests send as `model`; works before the presets loaded (the default
|
|
23
|
-
modelRef: (slot:
|
|
21
|
+
slotProfile: (slot: ModelRole) => ModelProfile | undefined;
|
|
22
|
+
/** What AI requests send as `model`; works before the Model presets loaded (the default Model preset of the role of `createEditor({ ai })`). */
|
|
23
|
+
modelRef: (slot: ModelRole) => ModelRef;
|
|
24
24
|
saveUserProfile: (profile: UserModelProfile) => void;
|
|
25
|
-
/** Also resets every
|
|
25
|
+
/** Also resets every Model role that ran on the profile to the server default. */
|
|
26
26
|
removeUserProfile: (id: string) => void;
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
29
|
* Model profiles the AI features run on, shared by all editors of the app (cached per `createEditorContext`, never
|
|
30
|
-
* process-global):
|
|
30
|
+
* process-global): Model presets (`backend.ai.models()`, requested once on first
|
|
31
31
|
* use, without keys) plus user profiles that live only in this browser's localStorage (their key goes with each
|
|
32
32
|
* request). Framework-free: `modelRef(slot)` is what AI requests send as `model`. Frameworks observe `presets`,
|
|
33
|
-
* `userProfiles` and `app.settings` (the
|
|
33
|
+
* `userProfiles` and `app.settings` (the Model role assignment is `settings.ai.roles`).
|
|
34
34
|
*/
|
|
35
35
|
export declare function modelProfiles(app: EditorContext): ModelProfilesModel;
|
|
36
36
|
//#endregion
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MODEL_ROLES } from "../../settings/values.js";
|
|
2
2
|
import { createStore } from "../../core/store.js";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
//#region src/features/ai/model-profiles.ts
|
|
@@ -28,15 +28,15 @@ function loadUserProfiles() {
|
|
|
28
28
|
function createModelProfiles(app) {
|
|
29
29
|
const presets = createStore([]);
|
|
30
30
|
const userProfiles = createStore(loadUserProfiles());
|
|
31
|
-
/** Default preset id per
|
|
32
|
-
let
|
|
33
|
-
const
|
|
31
|
+
/** Default Model preset id per Model role as the server reports it; until then the app's public AI configuration. */
|
|
32
|
+
let serverRoles = null;
|
|
33
|
+
const defaultRoles = app.ai?.roles ?? {
|
|
34
34
|
complete: "",
|
|
35
35
|
rewrite: "",
|
|
36
36
|
generate: ""
|
|
37
37
|
};
|
|
38
38
|
app.backend.ai?.models().then((response) => {
|
|
39
|
-
|
|
39
|
+
serverRoles = response.roles;
|
|
40
40
|
presets.set(response.presets);
|
|
41
41
|
}).catch((error) => {
|
|
42
42
|
console.warn("tiptap-editor: Modell-Presets konnten nicht geladen werden", error);
|
|
@@ -49,13 +49,13 @@ function createModelProfiles(app) {
|
|
|
49
49
|
source: "user"
|
|
50
50
|
}))];
|
|
51
51
|
const slotProfile = (slot) => {
|
|
52
|
-
const chosen = app.settings.get().ai.
|
|
53
|
-
const defaultId = (
|
|
52
|
+
const chosen = app.settings.get().ai.roles[slot];
|
|
53
|
+
const defaultId = (serverRoles ?? defaultRoles)[slot];
|
|
54
54
|
return profiles().find((p) => p.id === chosen) ?? presets.get().find((p) => p.id === defaultId) ?? presets.get()[0];
|
|
55
55
|
};
|
|
56
56
|
const modelRef = (slot) => {
|
|
57
57
|
const profile = slotProfile(slot);
|
|
58
|
-
if (!profile) return { preset: (
|
|
58
|
+
if (!profile) return { preset: (serverRoles ?? defaultRoles)[slot] };
|
|
59
59
|
const user = profile.source === "user" ? userProfiles.get().find((p) => p.id === profile.id) : void 0;
|
|
60
60
|
return user ? {
|
|
61
61
|
endpoint: user.endpoint,
|
|
@@ -74,9 +74,9 @@ function createModelProfiles(app) {
|
|
|
74
74
|
const next = userProfiles.get().filter((p) => p.id !== id);
|
|
75
75
|
userProfiles.set(next);
|
|
76
76
|
storeUserProfiles(next);
|
|
77
|
-
const
|
|
78
|
-
if (
|
|
79
|
-
for (const slot of
|
|
77
|
+
const roles = app.settings.get().ai.roles;
|
|
78
|
+
if (MODEL_ROLES.some((slot) => roles[slot] === id)) app.settings.update((s) => {
|
|
79
|
+
for (const slot of MODEL_ROLES) if (s.ai.roles[slot] === id) delete s.ai.roles[slot];
|
|
80
80
|
});
|
|
81
81
|
};
|
|
82
82
|
return {
|
|
@@ -92,10 +92,10 @@ function createModelProfiles(app) {
|
|
|
92
92
|
const models = /* @__PURE__ */ new WeakMap();
|
|
93
93
|
/**
|
|
94
94
|
* Model profiles the AI features run on, shared by all editors of the app (cached per `createEditorContext`, never
|
|
95
|
-
* process-global):
|
|
95
|
+
* process-global): Model presets (`backend.ai.models()`, requested once on first
|
|
96
96
|
* use, without keys) plus user profiles that live only in this browser's localStorage (their key goes with each
|
|
97
97
|
* request). Framework-free: `modelRef(slot)` is what AI requests send as `model`. Frameworks observe `presets`,
|
|
98
|
-
* `userProfiles` and `app.settings` (the
|
|
98
|
+
* `userProfiles` and `app.settings` (the Model role assignment is `settings.ai.roles`).
|
|
99
99
|
*/
|
|
100
100
|
function modelProfiles(app) {
|
|
101
101
|
let model = models.get(app);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-profiles.js","names":[],"sources":["../../../src/features/ai/model-profiles.ts"],"sourcesContent":["import { z } from 'zod'\nimport type { EditorContext } from '../../core/context'\nimport { createStore, type ReadonlyStore, type Store } from '../../core/store'\nimport {
|
|
1
|
+
{"version":3,"file":"model-profiles.js","names":[],"sources":["../../../src/features/ai/model-profiles.ts"],"sourcesContent":["import { z } from 'zod'\nimport type { EditorContext } from '../../core/context'\nimport { createStore, type ReadonlyStore, type Store } from '../../core/store'\nimport { MODEL_ROLES, type ModelRole } from '../../settings'\nimport type { ModelProfile, ModelRef, UserModelProfile } from './protocol'\n\nconst STORAGE_KEY = 'tiptap-editor:model-profiles'\n\n/** The model profiles of one app: see `modelProfiles`. */\nexport interface ModelProfilesModel {\n /** Server presets (`ai.models()`, without keys); empty until loaded. */\n presets: ReadonlyStore<ModelProfile[]>\n /** This browser's own profiles (localStorage). Change them through `saveUserProfile`/`removeUserProfile`. */\n userProfiles: Store<UserModelProfile[]>\n /** Presets, then user profiles. Reads the stores: call it again after either changed. */\n profiles: () => ModelProfile[]\n /**\n * Profile a Model role runs on: the one the settings assign to it, else the server's default Model preset for the Model role, else the\n * first Model preset; none before the Model presets loaded (unless the settings point at a user profile).\n */\n slotProfile: (slot: ModelRole) => ModelProfile | undefined\n /** What AI requests send as `model`; works before the Model presets loaded (the default Model preset of the role of `createEditor({ ai })`). */\n modelRef: (slot: ModelRole) => ModelRef\n saveUserProfile: (profile: UserModelProfile) => void\n /** Also resets every Model role that ran on the profile to the server default. */\n removeUserProfile: (id: string) => void\n}\n\nconst storedProfileSchema = z.object({ id: z.string(), label: z.string(), endpoint: z.string(), model: z.string(), apiKey: z.string() })\n\nfunction storeUserProfiles(profiles: UserModelProfile[]) {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(profiles))\n }\n catch {\n // Storage unavailable (e.g. privacy mode): the profiles last for this session only.\n }\n}\n\nfunction loadUserProfiles(): UserModelProfile[] {\n try {\n const stored: unknown = JSON.parse(localStorage.getItem(STORAGE_KEY) ?? '[]')\n if (Array.isArray(stored)) {\n return stored.flatMap((item) => {\n const parsed = storedProfileSchema.safeParse(item)\n return parsed.success ? [parsed.data] : []\n })\n }\n }\n catch {\n // Unreadable or corrupt storage: no user profiles.\n }\n return []\n}\n\nfunction createModelProfiles(app: EditorContext): ModelProfilesModel {\n const presets = createStore<ModelProfile[]>([])\n const userProfiles = createStore<UserModelProfile[]>(loadUserProfiles())\n /** Default Model preset id per Model role as the server reports it; until then the app's public AI configuration. */\n let serverRoles: Record<ModelRole, string> | null = null\n const defaultRoles: Record<ModelRole, string> = app.ai?.roles ?? { complete: '', rewrite: '', generate: '' }\n\n // A backend without `ai` has no Model presets: requests keep using the default Model presets of the Model roles by id.\n app.backend.ai?.models()\n .then((response) => {\n serverRoles = response.roles\n presets.set(response.presets)\n })\n .catch((error) => {\n // Requests keep using the default Model presets of the Model roles by id.\n console.warn('tiptap-editor: Modell-Presets konnten nicht geladen werden', error)\n })\n\n const profiles = (): ModelProfile[] => [\n ...presets.get(),\n ...userProfiles.get().map(({ id, label, endpoint, model }) => ({ id, label, endpoint, model, source: 'user' as const })),\n ]\n\n const slotProfile = (slot: ModelRole): ModelProfile | undefined => {\n const chosen = app.settings.get().ai.roles[slot]\n const defaultId = (serverRoles ?? defaultRoles)[slot]\n return profiles().find(p => p.id === chosen)\n ?? presets.get().find(p => p.id === defaultId)\n ?? presets.get()[0]\n }\n\n const modelRef = (slot: ModelRole): ModelRef => {\n const profile = slotProfile(slot)\n if (!profile) return { preset: (serverRoles ?? defaultRoles)[slot] }\n const user = profile.source === 'user' ? userProfiles.get().find(p => p.id === profile.id) : undefined\n return user ? { endpoint: user.endpoint, model: user.model, apiKey: user.apiKey } : { preset: profile.id }\n }\n\n const saveUserProfile = (profile: UserModelProfile) => {\n const current = userProfiles.get()\n const index = current.findIndex(p => p.id === profile.id)\n const next = index < 0 ? [...current, profile] : current.map((p, i) => (i === index ? profile : p))\n userProfiles.set(next)\n storeUserProfiles(next)\n }\n\n const removeUserProfile = (id: string) => {\n const next = userProfiles.get().filter(p => p.id !== id)\n userProfiles.set(next)\n storeUserProfiles(next)\n const roles = app.settings.get().ai.roles\n if (MODEL_ROLES.some(slot => roles[slot] === id)) {\n app.settings.update((s) => {\n for (const slot of MODEL_ROLES) {\n if (s.ai.roles[slot] === id) delete s.ai.roles[slot]\n }\n })\n }\n }\n\n return { presets, userProfiles, profiles, slotProfile, modelRef, saveUserProfile, removeUserProfile }\n}\n\nconst models = new WeakMap<EditorContext, ModelProfilesModel>()\n\n/**\n * Model profiles the AI features run on, shared by all editors of the app (cached per `createEditorContext`, never\n * process-global): Model presets (`backend.ai.models()`, requested once on first\n * use, without keys) plus user profiles that live only in this browser's localStorage (their key goes with each\n * request). Framework-free: `modelRef(slot)` is what AI requests send as `model`. Frameworks observe `presets`,\n * `userProfiles` and `app.settings` (the Model role assignment is `settings.ai.roles`).\n */\nexport function modelProfiles(app: EditorContext): ModelProfilesModel {\n let model = models.get(app)\n if (!model) {\n model = createModelProfiles(app)\n models.set(app, model)\n }\n return model\n}\n"],"mappings":"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"}
|
|
@@ -16,7 +16,7 @@ export type AgentOpType = typeof AGENT_OP_TYPES[number];
|
|
|
16
16
|
* One proposed edit as the model writes it: `update` replaces block `id` by `markdown`, `delete` removes block `id`,
|
|
17
17
|
* `add` inserts `markdown` (one or more blocks) after block `afterId` (`null`: at the start of the document; the key
|
|
18
18
|
* is required), `convert` turns block `id` into the block type `to` (a `CONVERT_TARGET_IDS` entry or
|
|
19
|
-
* `
|
|
19
|
+
* `typedBlock:<kind>`), keeping its content.
|
|
20
20
|
*/
|
|
21
21
|
export type ModelAgentOp = {
|
|
22
22
|
type: 'update';
|
|
@@ -86,7 +86,7 @@ export declare const AGENT_OP_OUTCOME_TEXT: Record<Locale, Record<AgentOpOutcome
|
|
|
86
86
|
export interface AgentTextOptions {
|
|
87
87
|
locale?: Locale;
|
|
88
88
|
}
|
|
89
|
-
/** `update Block X`, `add nach Block X`, `add am Dokumentanfang`, `convert Block X →
|
|
89
|
+
/** `update Block X`, `add nach Block X`, `add am Dokumentanfang`, `convert Block X → typedBlock:task` (`to` when known); English with `locale: 'en'`. */
|
|
90
90
|
export declare function agentOpSummary(op: {
|
|
91
91
|
type: AgentOpType;
|
|
92
92
|
target: string | null;
|
|
@@ -159,7 +159,7 @@ const AGENT_OP_OUTCOME_TEXT = {
|
|
|
159
159
|
de: AGENT_TEXTS.de.outcome,
|
|
160
160
|
en: AGENT_TEXTS.en.outcome
|
|
161
161
|
};
|
|
162
|
-
/** `update Block X`, `add nach Block X`, `add am Dokumentanfang`, `convert Block X →
|
|
162
|
+
/** `update Block X`, `add nach Block X`, `add am Dokumentanfang`, `convert Block X → typedBlock:task` (`to` when known); English with `locale: 'en'`. */
|
|
163
163
|
function agentOpSummary(op, { locale = "de" } = {}) {
|
|
164
164
|
const text = AGENT_TEXTS[locale].summary;
|
|
165
165
|
if (op.type === "convert" && op.to) return text.convert(op.target, op.to);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-ops.js","names":[],"sources":["../../../../src/features/ai/protocol/agent-ops.ts"],"sourcesContent":["// i18n-ignore-file: model-facing tool results, operation checks and decision texts (German by default, English on request; the model's language is not the editor's)\n/**\n * Agent operations of the document chat: the model proposes block edits through the `edit_document` tool, the server\n * checks every block ID against the document and the scope, and the client shows the valid ones as in-document review.\n */\nimport type { Locale } from '../../../i18n'\n\nimport { BLOCK_LINE_IDS_HINT, type BlockLines, stripBlockLineEcho } from './block-lines'\n\n/** Name of the tool the chat model calls to propose edits. */\nexport const AGENT_TOOL = 'edit_document'\n\n/** Per-turn limits: operations, Markdown per operation, IDs in a selection scope; retries after invalid IDs. */\nexport const AGENT_LIMITS = { ops: 50, markdown: 8000, scope: 5000, retries: 2 } as const\n\nexport const AGENT_OP_TYPES = ['add', 'update', 'delete', 'convert'] as const\nexport type AgentOpType = typeof AGENT_OP_TYPES[number]\n\n/**\n * One proposed edit as the model writes it: `update` replaces block `id` by `markdown`, `delete` removes block `id`,\n * `add` inserts `markdown` (one or more blocks) after block `afterId` (`null`: at the start of the document; the key\n * is required), `convert` turns block `id` into the block type `to` (a `CONVERT_TARGET_IDS` entry or\n * `composite:<kind>`), keeping its content.\n */\nexport type ModelAgentOp =\n | { type: 'update', id: string, markdown: string }\n | { type: 'delete', id: string }\n | { type: 'add', afterId: string | null, markdown: string }\n | { type: 'convert', id: string, to: string }\n\n/** A checked operation with the conversation-wide ID (`op1`, `op2`, …) that decisions refer to. */\nexport type AgentOp = ModelAgentOp & { op: string }\n\n/**\n * What became of an operation: decided in the review (`accepted`, `rejected`, `partial` for mixed hunks, `invalid`\n * when its text changed underneath), still `pending`, or never reviewed: the client found its block deleted since the\n * document went to the model (`stale`) or refused it as out of scope (`blocked`), or the review found nothing to show\n * (`unchanged`, `missing` block, `overlap` with open AI changes, `empty` result).\n */\nexport const AGENT_OP_OUTCOMES = ['accepted', 'rejected', 'partial', 'invalid', 'pending', 'unchanged', 'missing', 'stale', 'overlap', 'empty', 'blocked'] as const\nexport type AgentOpOutcome = typeof AGENT_OP_OUTCOMES[number]\n\n/** Decision state of an earlier operation, sent with the next user message. */\nexport interface AgentOpFeedback { op: string, type: AgentOpType, target: string | null, outcome: AgentOpOutcome }\n\n/**\n * Why an operation was dropped: unknown block ID, ID outside the scope, a missing/invalid field, a block edited twice,\n * too many ops, a `convert` target that is not offered, a block inside another block that an operation of the same\n * answer replaces or deletes (`inside`).\n */\nexport type AgentOpProblemReason = 'unknown' | 'scope' | 'field' | 'duplicate' | 'limit' | 'target' | 'inside'\n\n/** A dropped operation: its 1-based position in the tool call, type and target as far as readable, and the offending ID. */\nexport interface AgentOpProblem { index: number, type: string | null, id: string | null, reason: AgentOpProblemReason, detail: string }\n\n/**\n * Where operations may point: `lines` the block IDs of the document text and which blocks lie inside which (see\n * `readBlockLines`); `allowed` the selection scope (null: the whole document); `targets` the block types `convert`\n * may turn a block into; `locale` the language of the problem details (default `de`).\n */\nexport interface AgentOpContext { lines: BlockLines, allowed: ReadonlySet<string> | null, targets: ReadonlySet<string>, locale?: Locale }\n\n/** The block an operation targets: `update`/`delete` its `id`, `add` its `afterId` (null: document start). */\nexport function agentOpTarget(op: ModelAgentOp): string | null {\n return op.type === 'add' ? op.afterId : op.id\n}\n\n/**\n * Every model-facing text of the agent protocol, per locale (the editor's own prompts in chat.ts stay German). Selected\n * by the `locale` option of the functions below; `de` is the default and what existing hosts receive.\n */\ninterface AgentTexts {\n /** How an outcome reads for the model. */\n outcome: Record<AgentOpOutcome, string>\n summary: {\n convert: (target: string | null, to: string) => string\n block: (type: string, target: string | null) => string\n addStart: string\n addAfter: (target: string) => string\n }\n problem: {\n limit: (max: number) => string\n type: (allowed: string) => string\n addAtStart: string\n idMissing: (field: string) => string\n unknownId: (id: string) => string\n outsideScope: (id: string) => string\n duplicate: (id: string) => string\n toMissing: string\n badTarget: (to: string, allowed: string) => string\n markdownMissing: string\n markdownMissingUpdate: string\n markdownTooLong: (max: number) => string\n unreadable: string\n afterIdMissing: string\n afterIdMissingScoped: string\n inside: (target: string, owner: string, ownerIndex: number, deletes: boolean) => string\n }\n retry: {\n failed: string\n failedPartial: string\n invalidIds: (ids: string) => string\n operation: (index: number, type: string | null, detail: string) => string\n scoped: string\n unscoped: string\n inside: string\n again: (tool: string) => string\n againPartial: (tool: string) => string\n }\n shown: {\n shown: (ops: string) => string\n none: string\n dropped: (count: number) => string\n decisions: string\n }\n feedback: (decisions: string) => string\n}\n\nconst AGENT_TEXTS: Record<Locale, AgentTexts> = {\n de: {\n outcome: {\n accepted: 'übernommen',\n rejected: 'abgelehnt',\n partial: 'teilweise übernommen',\n invalid: 'verfallen, weil der Text inzwischen anders geändert wurde',\n pending: 'noch nicht entschieden',\n unchanged: 'nicht angezeigt, weil er dem vorhandenen Text entspricht',\n missing: 'nicht angezeigt, weil der Block nicht mehr existiert',\n overlap: 'nicht angezeigt, weil an der Stelle noch andere KI-Änderungen offen sind',\n empty: 'nicht angezeigt, weil der Inhalt leer ist',\n stale: 'nicht angezeigt: Block wurde inzwischen gelöscht',\n blocked: 'blockiert, weil er außerhalb des erlaubten Bereichs liegt',\n },\n summary: {\n convert: (target, to) => `convert Block ${target} → ${to}`,\n block: (type, target) => `${type} Block ${target}`,\n addStart: 'add am Dokumentanfang',\n addAfter: target => `add nach Block ${target}`,\n },\n problem: {\n limit: max => `mehr als ${max} Operationen`,\n type: allowed => `unbekannter oder fehlender Typ (erlaubt: ${allowed})`,\n addAtStart: 'Einfügen am Dokumentanfang liegt außerhalb der Auswahl; afterId muss ein ausgewählter Block sein',\n idMissing: field => `${field} fehlt`,\n unknownId: id => `die ID „${id}“ gibt es im Dokument nicht`,\n outsideScope: id => `die ID „${id}“ liegt außerhalb der Auswahl`,\n duplicate: id => `der Block „${id}“ wird mehrfach geändert oder gelöscht`,\n toMissing: 'to fehlt',\n badTarget: (to, allowed) => `„${to}“ ist kein erlaubter Blocktyp für to (erlaubt: ${allowed})`,\n markdownMissing: 'markdown fehlt',\n markdownMissingUpdate: 'markdown fehlt (zum Entfernen „delete“ verwenden)',\n markdownTooLong: max => `markdown ist länger als ${max} Zeichen`,\n unreadable: 'die Eingabe war kein Objekt mit der Liste „ops“',\n afterIdMissing: 'afterId fehlt; für den Dokumentanfang ausdrücklich null schreiben',\n afterIdMissingScoped: 'afterId fehlt; es muss ein ausgewählter Block sein',\n inside: (target, owner, ownerIndex, deletes) => `Block ${target} liegt in ${owner}, das Operation ${ownerIndex} ${deletes ? 'löscht' : 'ersetzt'}`,\n },\n retry: {\n failed: 'Fehler: Die Operationen wurden nicht angewendet, weil einige ungültig sind.',\n failedPartial: 'Fehler: Einige Operationen sind ungültig und wurden verworfen; die übrigen werden zur Prüfung angezeigt.',\n invalidIds: ids => `Ungültige IDs: ${ids}`,\n operation: (index, type, detail) => `- Operation ${index}${type ? ` (${type})` : ''}: ${detail}`,\n inside: 'Eine Operation auf einen Block innerhalb eines ersetzten oder gelöschten Blocks entfällt: die Operation auf den äußeren Block gilt. Soll der innere Block mitgeändert werden, schreibe die Änderung in das Markdown der äußeren Operation.',\n scoped: 'Verwende nur IDs aus dem Bearbeitungsbereich (siehe Nachricht); erfinde keine IDs.',\n unscoped: BLOCK_LINE_IDS_HINT,\n again: tool => `Rufe ${tool} erneut mit der vollständigen, korrigierten Liste aller Operationen auf. Lass Operationen weg, die sich nicht korrigieren lassen.`,\n againPartial: tool => `Rufe ${tool} erneut nur mit den korrigierten Fassungen der oben genannten Operationen auf; wiederhole die angezeigten nicht. Lass Operationen weg, die sich nicht korrigieren lassen.`,\n },\n shown: {\n shown: ops => `Zur Prüfung im Dokument angezeigt: ${ops}.`,\n none: 'Keine der Operationen wurde angezeigt.',\n dropped: count => `${count} Operation(en) mit ungültigen IDs wurden verworfen; die Nutzerin bzw. der Nutzer wurde darauf hingewiesen.`,\n decisions: 'Die Nutzerin bzw. der Nutzer übernimmt oder verwirft jede Änderung im Dokument; die Entscheidungen folgen mit einer späteren Nachricht.',\n },\n feedback: decisions => `Entscheidungen zu deinen letzten Vorschlägen: ${decisions}.`,\n },\n en: {\n outcome: {\n accepted: 'accepted',\n rejected: 'rejected',\n partial: 'partially accepted',\n invalid: 'lapsed because the text was changed in the meantime',\n pending: 'not decided yet',\n unchanged: 'not shown because it matches the existing text',\n missing: 'not shown because the block no longer exists',\n overlap: 'not shown because other AI changes are still open at that place',\n empty: 'not shown because the content is empty',\n stale: 'not shown: the block was deleted in the meantime',\n blocked: 'blocked because it lies outside the allowed scope',\n },\n summary: {\n convert: (target, to) => `convert block ${target} → ${to}`,\n block: (type, target) => `${type} block ${target}`,\n addStart: 'add at the start of the document',\n addAfter: target => `add after block ${target}`,\n },\n problem: {\n limit: max => `more than ${max} operations`,\n type: allowed => `unknown or missing type (allowed: ${allowed})`,\n addAtStart: 'inserting at the start of the document is outside the selection; afterId must be a selected block',\n idMissing: field => `${field} is missing`,\n unknownId: id => `the ID \"${id}\" does not exist in the document`,\n outsideScope: id => `the ID \"${id}\" is outside the selection`,\n duplicate: id => `the block \"${id}\" is changed or deleted more than once`,\n toMissing: 'to is missing',\n badTarget: (to, allowed) => `\"${to}\" is not an allowed block type for to (allowed: ${allowed})`,\n markdownMissing: 'markdown is missing',\n markdownMissingUpdate: 'markdown is missing (use \"delete\" to remove a block)',\n markdownTooLong: max => `markdown is longer than ${max} characters`,\n unreadable: 'the input was not an object with the list \"ops\"',\n afterIdMissing: 'afterId is missing; write null explicitly for the start of the document',\n afterIdMissingScoped: 'afterId is missing; it must be a selected block',\n inside: (target, owner, ownerIndex, deletes) => `block ${target} lies inside ${owner}, which operation ${ownerIndex} ${deletes ? 'deletes' : 'replaces'}`,\n },\n retry: {\n failed: 'Error: The operations were not applied because some of them are invalid.',\n failedPartial: 'Error: Some operations are invalid and were dropped; the others are shown for review.',\n invalidIds: ids => `Invalid IDs: ${ids}`,\n operation: (index, type, detail) => `- Operation ${index}${type ? ` (${type})` : ''}: ${detail}`,\n inside: 'An operation on a block inside a replaced or deleted block is dropped: the operation on the outer block applies. To change the inner block as well, write the change into the Markdown of the outer operation.',\n scoped: 'Use only IDs from the editing scope (see message); do not invent IDs.',\n unscoped: 'Use only IDs that appear in square brackets in the document; do not invent IDs.',\n again: tool => `Call ${tool} again with the complete, corrected list of all operations. Leave out operations that cannot be corrected.`,\n againPartial: tool => `Call ${tool} again with corrected versions of only the operations listed above; do not repeat the shown ones. Leave out operations that cannot be corrected.`,\n },\n shown: {\n shown: ops => `Shown in the document for review: ${ops}.`,\n none: 'None of the operations were shown.',\n dropped: count => `${count} operation(s) with invalid IDs were dropped; the user has been notified.`,\n decisions: 'The user accepts or rejects each change in the document; the decisions follow with a later message.',\n },\n feedback: decisions => `Decisions on your latest proposals: ${decisions}.`,\n },\n}\n\n/** How an outcome reads for the model, per locale; the chat shows the catalog's `ai.opTitle.*` texts. */\nexport const AGENT_OP_OUTCOME_TEXT: Record<Locale, Record<AgentOpOutcome, string>> = {\n de: AGENT_TEXTS.de.outcome,\n en: AGENT_TEXTS.en.outcome,\n}\n\n/** Text options of the model-facing functions: `locale` selects the language (default `de`). */\nexport interface AgentTextOptions { locale?: Locale }\n\n/** `update Block X`, `add nach Block X`, `add am Dokumentanfang`, `convert Block X → composite:task` (`to` when known); English with `locale: 'en'`. */\nexport function agentOpSummary(op: { type: AgentOpType, target: string | null, to?: string }, { locale = 'de' }: AgentTextOptions = {}): string {\n const text = AGENT_TEXTS[locale].summary\n if (op.type === 'convert' && op.to) return text.convert(op.target, op.to)\n if (op.type !== 'add') return text.block(op.type, op.target)\n return op.target === null ? text.addStart : text.addAfter(op.target)\n}\n\n/**\n * Checks the raw `ops` of `edit_document` calls: every ID must exist and lie in the scope (`add` needs its `afterId`\n * key, `null` for the document start, and in a selection scope an `afterId` from the selection), fields must be\n * present, a `convert` target must be one of `targets`, a block is updated, converted or deleted at most once, and no\n * operation may point into a block (`lines.below`) that another operation replaces (`update`) or deletes: the\n * operation on the outer block wins. Several `add`s after the same block are fine; the client inserts them in the\n * order they were written. Returns the valid operations in order and the problems of the others; the problems'\n * `detail` is written in `context.locale` (default `de`).\n */\nexport function checkAgentOps(raw: readonly unknown[], context: AgentOpContext): { valid: ModelAgentOp[], problems: AgentOpProblem[] } {\n const accepted: { op: ModelAgentOp, index: number }[] = []\n const problems: AgentOpProblem[] = []\n const edited = new Set<string>()\n const text = AGENT_TEXTS[context.locale ?? 'de'].problem\n const known = (id: string) => context.lines.ids.has(id)\n\n raw.forEach((entry, i) => {\n const index = i + 1\n const value = (entry && typeof entry === 'object' ? entry : {}) as Record<string, unknown>\n const type = typeof value.type === 'string' ? value.type : null\n const problem = (reason: AgentOpProblemReason, id: string | null, detail: string) => problems.push({ index, type, id, reason, detail })\n const accept = (op: ModelAgentOp) => accepted.push({ op, index })\n\n if (index > AGENT_LIMITS.ops) return problem('limit', null, text.limit(AGENT_LIMITS.ops))\n if (!type || !(AGENT_OP_TYPES as readonly string[]).includes(type)) return problem('field', null, text.type(AGENT_OP_TYPES.join(', ')))\n\n const idField = type === 'add' ? 'afterId' : 'id'\n const rawId = value[idField]\n // `afterId: null` is the document start; a forgotten key must not become one.\n if (type === 'add' && rawId === undefined) {\n return problem('field', null, context.allowed ? text.afterIdMissingScoped : text.afterIdMissing)\n }\n if (type === 'add' && rawId === null) {\n if (context.allowed) return problem('scope', null, text.addAtStart)\n }\n else if (typeof rawId !== 'string' || !rawId.trim()) {\n return problem('field', null, text.idMissing(idField))\n }\n const id = typeof rawId === 'string' ? rawId.trim() : null\n if (id !== null) {\n if (!known(id)) return problem('unknown', id, text.unknownId(id))\n if (context.allowed && !context.allowed.has(id)) return problem('scope', id, text.outsideScope(id))\n }\n\n if (type === 'delete') {\n if (edited.has(id!)) return problem('duplicate', id, text.duplicate(id!))\n edited.add(id!)\n return accept({ type, id: id! })\n }\n\n if (type === 'convert') {\n const to = typeof value.to === 'string' ? value.to.trim() : ''\n if (!to) return problem('field', id, text.toMissing)\n if (!context.targets.has(to)) return problem('target', id, text.badTarget(to, [...context.targets].join(', ')))\n if (edited.has(id!)) return problem('duplicate', id, text.duplicate(id!))\n edited.add(id!)\n return accept({ type, id: id!, to })\n }\n\n const markdown = typeof value.markdown === 'string' ? stripBlockLineEcho(value.markdown, known).trim() : ''\n if (!markdown) return problem('field', id, type === 'update' ? text.markdownMissingUpdate : text.markdownMissing)\n if (markdown.length > AGENT_LIMITS.markdown) return problem('field', id, text.markdownTooLong(AGENT_LIMITS.markdown))\n if (type === 'add') return accept({ type, afterId: id, markdown })\n if (edited.has(id!)) return problem('duplicate', id, text.duplicate(id!))\n edited.add(id!)\n accept({ type: 'update', id: id!, markdown })\n })\n\n // An operation on a block inside another operation's block is dropped, naming the outermost operation that covers it.\n const owners = accepted.filter(({ op }) => op.type === 'update' || op.type === 'delete')\n const covering = ({ op }: typeof accepted[number]) => {\n const target = agentOpTarget(op)\n return target === null ? [] : owners.filter(owner => context.lines.below(agentOpTarget(owner.op)!).has(target))\n }\n const valid: ModelAgentOp[] = []\n for (const entry of accepted) {\n const cover = covering(entry)\n const owner = cover.find(candidate => !covering(candidate).length) ?? cover[0]\n if (!owner) {\n valid.push(entry.op)\n continue\n }\n const target = agentOpTarget(entry.op)!\n problems.push({\n index: entry.index,\n type: entry.op.type,\n id: target,\n reason: 'inside',\n detail: text.inside(target, agentOpTarget(owner.op)!, owner.index, owner.op.type === 'delete'),\n })\n }\n problems.sort((a, b) => a.index - b.index)\n return { valid, problems }\n}\n\n/** The problem for a tool call whose input was no object with the list `ops` (index 0), worded in `locale` (default `de`). */\nexport function agentUnreadableProblem({ locale = 'de' }: AgentTextOptions = {}): AgentOpProblem {\n return { index: 0, type: null, id: null, reason: 'field', detail: AGENT_TEXTS[locale].problem.unreadable }\n}\n\n/**\n * Tool result asking the model to call `tool` (default `edit_document`, the host's own tool name when it exposes the\n * operations under another one) again without the invalid operations' mistakes; worded in `locale` (default `de`).\n * By default nothing was applied and the model resends the whole list; with `partial` the host already shows the\n * valid operations, so the model resends only corrected versions of the listed ones.\n */\nexport function agentRetryMessage(\n problems: readonly AgentOpProblem[],\n scoped: boolean,\n { locale = 'de', tool = AGENT_TOOL, partial = false }: AgentTextOptions & { tool?: string, partial?: boolean } = {},\n): string {\n const text = AGENT_TEXTS[locale].retry\n const ids = [...new Set(problems.filter(p => p.reason !== 'inside').map(p => p.id).filter((id): id is string => !!id))]\n return [\n partial ? text.failedPartial : text.failed,\n ...(ids.length ? [text.invalidIds(ids.join(', '))] : []),\n ...problems.map(p => text.operation(p.index, p.type, p.detail)),\n ...(problems.some(p => p.reason === 'inside') ? [text.inside] : []),\n scoped ? text.scoped : text.unscoped,\n partial ? text.againPartial(tool) : text.again(tool),\n ].join('\\n')\n}\n\n/** Tool result of a past `edit_document` call: which operations were shown for review, and how many were dropped; worded in `locale` (default `de`). */\nexport function agentShownMessage(ops: readonly AgentOp[], dropped: number, { locale = 'de' }: AgentTextOptions = {}): string {\n const text = AGENT_TEXTS[locale].shown\n const lines = ops.length\n ? [text.shown(ops.map(op => `${op.op} (${agentOpSummary({ ...op, target: agentOpTarget(op) }, { locale })})`).join(', '))]\n : [text.none]\n if (dropped) lines.push(text.dropped(dropped))\n lines.push(text.decisions)\n return lines.join(' ')\n}\n\n/** „Entscheidungen zu deinen letzten Vorschlägen: op1 (update Block X) abgelehnt; …“ (English with `locale: 'en'`), or '' without feedback. */\nexport function agentFeedbackText(feedback: readonly AgentOpFeedback[], { locale = 'de' }: AgentTextOptions = {}): string {\n if (!feedback.length) return ''\n const outcome = AGENT_TEXTS[locale].outcome\n return AGENT_TEXTS[locale].feedback(feedback.map(f => `${f.op} (${agentOpSummary(f, { locale })}) ${outcome[f.outcome]}`).join('; '))\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"agent-ops.js","names":[],"sources":["../../../../src/features/ai/protocol/agent-ops.ts"],"sourcesContent":["// i18n-ignore-file: model-facing tool results, operation checks and decision texts (German by default, English on request; the model's language is not the editor's)\n/**\n * Agent operations of the document chat: the model proposes block edits through the `edit_document` tool, the server\n * checks every block ID against the document and the scope, and the client shows the valid ones as in-document review.\n */\nimport type { Locale } from '../../../i18n'\n\nimport { BLOCK_LINE_IDS_HINT, type BlockLines, stripBlockLineEcho } from './block-lines'\n\n/** Name of the tool the chat model calls to propose edits. */\nexport const AGENT_TOOL = 'edit_document'\n\n/** Per-turn limits: operations, Markdown per operation, IDs in a selection scope; retries after invalid IDs. */\nexport const AGENT_LIMITS = { ops: 50, markdown: 8000, scope: 5000, retries: 2 } as const\n\nexport const AGENT_OP_TYPES = ['add', 'update', 'delete', 'convert'] as const\nexport type AgentOpType = typeof AGENT_OP_TYPES[number]\n\n/**\n * One proposed edit as the model writes it: `update` replaces block `id` by `markdown`, `delete` removes block `id`,\n * `add` inserts `markdown` (one or more blocks) after block `afterId` (`null`: at the start of the document; the key\n * is required), `convert` turns block `id` into the block type `to` (a `CONVERT_TARGET_IDS` entry or\n * `typedBlock:<kind>`), keeping its content.\n */\nexport type ModelAgentOp =\n | { type: 'update', id: string, markdown: string }\n | { type: 'delete', id: string }\n | { type: 'add', afterId: string | null, markdown: string }\n | { type: 'convert', id: string, to: string }\n\n/** A checked operation with the conversation-wide ID (`op1`, `op2`, …) that decisions refer to. */\nexport type AgentOp = ModelAgentOp & { op: string }\n\n/**\n * What became of an operation: decided in the review (`accepted`, `rejected`, `partial` for mixed hunks, `invalid`\n * when its text changed underneath), still `pending`, or never reviewed: the client found its block deleted since the\n * document went to the model (`stale`) or refused it as out of scope (`blocked`), or the review found nothing to show\n * (`unchanged`, `missing` block, `overlap` with open AI changes, `empty` result).\n */\nexport const AGENT_OP_OUTCOMES = ['accepted', 'rejected', 'partial', 'invalid', 'pending', 'unchanged', 'missing', 'stale', 'overlap', 'empty', 'blocked'] as const\nexport type AgentOpOutcome = typeof AGENT_OP_OUTCOMES[number]\n\n/** Decision state of an earlier operation, sent with the next user message. */\nexport interface AgentOpFeedback { op: string, type: AgentOpType, target: string | null, outcome: AgentOpOutcome }\n\n/**\n * Why an operation was dropped: unknown block ID, ID outside the scope, a missing/invalid field, a block edited twice,\n * too many ops, a `convert` target that is not offered, a block inside another block that an operation of the same\n * answer replaces or deletes (`inside`).\n */\nexport type AgentOpProblemReason = 'unknown' | 'scope' | 'field' | 'duplicate' | 'limit' | 'target' | 'inside'\n\n/** A dropped operation: its 1-based position in the tool call, type and target as far as readable, and the offending ID. */\nexport interface AgentOpProblem { index: number, type: string | null, id: string | null, reason: AgentOpProblemReason, detail: string }\n\n/**\n * Where operations may point: `lines` the block IDs of the document text and which blocks lie inside which (see\n * `readBlockLines`); `allowed` the selection scope (null: the whole document); `targets` the block types `convert`\n * may turn a block into; `locale` the language of the problem details (default `de`).\n */\nexport interface AgentOpContext { lines: BlockLines, allowed: ReadonlySet<string> | null, targets: ReadonlySet<string>, locale?: Locale }\n\n/** The block an operation targets: `update`/`delete` its `id`, `add` its `afterId` (null: document start). */\nexport function agentOpTarget(op: ModelAgentOp): string | null {\n return op.type === 'add' ? op.afterId : op.id\n}\n\n/**\n * Every model-facing text of the agent protocol, per locale (the editor's own prompts in chat.ts stay German). Selected\n * by the `locale` option of the functions below; `de` is the default and what existing hosts receive.\n */\ninterface AgentTexts {\n /** How an outcome reads for the model. */\n outcome: Record<AgentOpOutcome, string>\n summary: {\n convert: (target: string | null, to: string) => string\n block: (type: string, target: string | null) => string\n addStart: string\n addAfter: (target: string) => string\n }\n problem: {\n limit: (max: number) => string\n type: (allowed: string) => string\n addAtStart: string\n idMissing: (field: string) => string\n unknownId: (id: string) => string\n outsideScope: (id: string) => string\n duplicate: (id: string) => string\n toMissing: string\n badTarget: (to: string, allowed: string) => string\n markdownMissing: string\n markdownMissingUpdate: string\n markdownTooLong: (max: number) => string\n unreadable: string\n afterIdMissing: string\n afterIdMissingScoped: string\n inside: (target: string, owner: string, ownerIndex: number, deletes: boolean) => string\n }\n retry: {\n failed: string\n failedPartial: string\n invalidIds: (ids: string) => string\n operation: (index: number, type: string | null, detail: string) => string\n scoped: string\n unscoped: string\n inside: string\n again: (tool: string) => string\n againPartial: (tool: string) => string\n }\n shown: {\n shown: (ops: string) => string\n none: string\n dropped: (count: number) => string\n decisions: string\n }\n feedback: (decisions: string) => string\n}\n\nconst AGENT_TEXTS: Record<Locale, AgentTexts> = {\n de: {\n outcome: {\n accepted: 'übernommen',\n rejected: 'abgelehnt',\n partial: 'teilweise übernommen',\n invalid: 'verfallen, weil der Text inzwischen anders geändert wurde',\n pending: 'noch nicht entschieden',\n unchanged: 'nicht angezeigt, weil er dem vorhandenen Text entspricht',\n missing: 'nicht angezeigt, weil der Block nicht mehr existiert',\n overlap: 'nicht angezeigt, weil an der Stelle noch andere KI-Änderungen offen sind',\n empty: 'nicht angezeigt, weil der Inhalt leer ist',\n stale: 'nicht angezeigt: Block wurde inzwischen gelöscht',\n blocked: 'blockiert, weil er außerhalb des erlaubten Bereichs liegt',\n },\n summary: {\n convert: (target, to) => `convert Block ${target} → ${to}`,\n block: (type, target) => `${type} Block ${target}`,\n addStart: 'add am Dokumentanfang',\n addAfter: target => `add nach Block ${target}`,\n },\n problem: {\n limit: max => `mehr als ${max} Operationen`,\n type: allowed => `unbekannter oder fehlender Typ (erlaubt: ${allowed})`,\n addAtStart: 'Einfügen am Dokumentanfang liegt außerhalb der Auswahl; afterId muss ein ausgewählter Block sein',\n idMissing: field => `${field} fehlt`,\n unknownId: id => `die ID „${id}“ gibt es im Dokument nicht`,\n outsideScope: id => `die ID „${id}“ liegt außerhalb der Auswahl`,\n duplicate: id => `der Block „${id}“ wird mehrfach geändert oder gelöscht`,\n toMissing: 'to fehlt',\n badTarget: (to, allowed) => `„${to}“ ist kein erlaubter Blocktyp für to (erlaubt: ${allowed})`,\n markdownMissing: 'markdown fehlt',\n markdownMissingUpdate: 'markdown fehlt (zum Entfernen „delete“ verwenden)',\n markdownTooLong: max => `markdown ist länger als ${max} Zeichen`,\n unreadable: 'die Eingabe war kein Objekt mit der Liste „ops“',\n afterIdMissing: 'afterId fehlt; für den Dokumentanfang ausdrücklich null schreiben',\n afterIdMissingScoped: 'afterId fehlt; es muss ein ausgewählter Block sein',\n inside: (target, owner, ownerIndex, deletes) => `Block ${target} liegt in ${owner}, das Operation ${ownerIndex} ${deletes ? 'löscht' : 'ersetzt'}`,\n },\n retry: {\n failed: 'Fehler: Die Operationen wurden nicht angewendet, weil einige ungültig sind.',\n failedPartial: 'Fehler: Einige Operationen sind ungültig und wurden verworfen; die übrigen werden zur Prüfung angezeigt.',\n invalidIds: ids => `Ungültige IDs: ${ids}`,\n operation: (index, type, detail) => `- Operation ${index}${type ? ` (${type})` : ''}: ${detail}`,\n inside: 'Eine Operation auf einen Block innerhalb eines ersetzten oder gelöschten Blocks entfällt: die Operation auf den äußeren Block gilt. Soll der innere Block mitgeändert werden, schreibe die Änderung in das Markdown der äußeren Operation.',\n scoped: 'Verwende nur IDs aus dem Bearbeitungsbereich (siehe Nachricht); erfinde keine IDs.',\n unscoped: BLOCK_LINE_IDS_HINT,\n again: tool => `Rufe ${tool} erneut mit der vollständigen, korrigierten Liste aller Operationen auf. Lass Operationen weg, die sich nicht korrigieren lassen.`,\n againPartial: tool => `Rufe ${tool} erneut nur mit den korrigierten Fassungen der oben genannten Operationen auf; wiederhole die angezeigten nicht. Lass Operationen weg, die sich nicht korrigieren lassen.`,\n },\n shown: {\n shown: ops => `Zur Prüfung im Dokument angezeigt: ${ops}.`,\n none: 'Keine der Operationen wurde angezeigt.',\n dropped: count => `${count} Operation(en) mit ungültigen IDs wurden verworfen; die Nutzerin bzw. der Nutzer wurde darauf hingewiesen.`,\n decisions: 'Die Nutzerin bzw. der Nutzer übernimmt oder verwirft jede Änderung im Dokument; die Entscheidungen folgen mit einer späteren Nachricht.',\n },\n feedback: decisions => `Entscheidungen zu deinen letzten Vorschlägen: ${decisions}.`,\n },\n en: {\n outcome: {\n accepted: 'accepted',\n rejected: 'rejected',\n partial: 'partially accepted',\n invalid: 'lapsed because the text was changed in the meantime',\n pending: 'not decided yet',\n unchanged: 'not shown because it matches the existing text',\n missing: 'not shown because the block no longer exists',\n overlap: 'not shown because other AI changes are still open at that place',\n empty: 'not shown because the content is empty',\n stale: 'not shown: the block was deleted in the meantime',\n blocked: 'blocked because it lies outside the allowed scope',\n },\n summary: {\n convert: (target, to) => `convert block ${target} → ${to}`,\n block: (type, target) => `${type} block ${target}`,\n addStart: 'add at the start of the document',\n addAfter: target => `add after block ${target}`,\n },\n problem: {\n limit: max => `more than ${max} operations`,\n type: allowed => `unknown or missing type (allowed: ${allowed})`,\n addAtStart: 'inserting at the start of the document is outside the selection; afterId must be a selected block',\n idMissing: field => `${field} is missing`,\n unknownId: id => `the ID \"${id}\" does not exist in the document`,\n outsideScope: id => `the ID \"${id}\" is outside the selection`,\n duplicate: id => `the block \"${id}\" is changed or deleted more than once`,\n toMissing: 'to is missing',\n badTarget: (to, allowed) => `\"${to}\" is not an allowed block type for to (allowed: ${allowed})`,\n markdownMissing: 'markdown is missing',\n markdownMissingUpdate: 'markdown is missing (use \"delete\" to remove a block)',\n markdownTooLong: max => `markdown is longer than ${max} characters`,\n unreadable: 'the input was not an object with the list \"ops\"',\n afterIdMissing: 'afterId is missing; write null explicitly for the start of the document',\n afterIdMissingScoped: 'afterId is missing; it must be a selected block',\n inside: (target, owner, ownerIndex, deletes) => `block ${target} lies inside ${owner}, which operation ${ownerIndex} ${deletes ? 'deletes' : 'replaces'}`,\n },\n retry: {\n failed: 'Error: The operations were not applied because some of them are invalid.',\n failedPartial: 'Error: Some operations are invalid and were dropped; the others are shown for review.',\n invalidIds: ids => `Invalid IDs: ${ids}`,\n operation: (index, type, detail) => `- Operation ${index}${type ? ` (${type})` : ''}: ${detail}`,\n inside: 'An operation on a block inside a replaced or deleted block is dropped: the operation on the outer block applies. To change the inner block as well, write the change into the Markdown of the outer operation.',\n scoped: 'Use only IDs from the editing scope (see message); do not invent IDs.',\n unscoped: 'Use only IDs that appear in square brackets in the document; do not invent IDs.',\n again: tool => `Call ${tool} again with the complete, corrected list of all operations. Leave out operations that cannot be corrected.`,\n againPartial: tool => `Call ${tool} again with corrected versions of only the operations listed above; do not repeat the shown ones. Leave out operations that cannot be corrected.`,\n },\n shown: {\n shown: ops => `Shown in the document for review: ${ops}.`,\n none: 'None of the operations were shown.',\n dropped: count => `${count} operation(s) with invalid IDs were dropped; the user has been notified.`,\n decisions: 'The user accepts or rejects each change in the document; the decisions follow with a later message.',\n },\n feedback: decisions => `Decisions on your latest proposals: ${decisions}.`,\n },\n}\n\n/** How an outcome reads for the model, per locale; the chat shows the catalog's `ai.opTitle.*` texts. */\nexport const AGENT_OP_OUTCOME_TEXT: Record<Locale, Record<AgentOpOutcome, string>> = {\n de: AGENT_TEXTS.de.outcome,\n en: AGENT_TEXTS.en.outcome,\n}\n\n/** Text options of the model-facing functions: `locale` selects the language (default `de`). */\nexport interface AgentTextOptions { locale?: Locale }\n\n/** `update Block X`, `add nach Block X`, `add am Dokumentanfang`, `convert Block X → typedBlock:task` (`to` when known); English with `locale: 'en'`. */\nexport function agentOpSummary(op: { type: AgentOpType, target: string | null, to?: string }, { locale = 'de' }: AgentTextOptions = {}): string {\n const text = AGENT_TEXTS[locale].summary\n if (op.type === 'convert' && op.to) return text.convert(op.target, op.to)\n if (op.type !== 'add') return text.block(op.type, op.target)\n return op.target === null ? text.addStart : text.addAfter(op.target)\n}\n\n/**\n * Checks the raw `ops` of `edit_document` calls: every ID must exist and lie in the scope (`add` needs its `afterId`\n * key, `null` for the document start, and in a selection scope an `afterId` from the selection), fields must be\n * present, a `convert` target must be one of `targets`, a block is updated, converted or deleted at most once, and no\n * operation may point into a block (`lines.below`) that another operation replaces (`update`) or deletes: the\n * operation on the outer block wins. Several `add`s after the same block are fine; the client inserts them in the\n * order they were written. Returns the valid operations in order and the problems of the others; the problems'\n * `detail` is written in `context.locale` (default `de`).\n */\nexport function checkAgentOps(raw: readonly unknown[], context: AgentOpContext): { valid: ModelAgentOp[], problems: AgentOpProblem[] } {\n const accepted: { op: ModelAgentOp, index: number }[] = []\n const problems: AgentOpProblem[] = []\n const edited = new Set<string>()\n const text = AGENT_TEXTS[context.locale ?? 'de'].problem\n const known = (id: string) => context.lines.ids.has(id)\n\n raw.forEach((entry, i) => {\n const index = i + 1\n const value = (entry && typeof entry === 'object' ? entry : {}) as Record<string, unknown>\n const type = typeof value.type === 'string' ? value.type : null\n const problem = (reason: AgentOpProblemReason, id: string | null, detail: string) => problems.push({ index, type, id, reason, detail })\n const accept = (op: ModelAgentOp) => accepted.push({ op, index })\n\n if (index > AGENT_LIMITS.ops) return problem('limit', null, text.limit(AGENT_LIMITS.ops))\n if (!type || !(AGENT_OP_TYPES as readonly string[]).includes(type)) return problem('field', null, text.type(AGENT_OP_TYPES.join(', ')))\n\n const idField = type === 'add' ? 'afterId' : 'id'\n const rawId = value[idField]\n // `afterId: null` is the document start; a forgotten key must not become one.\n if (type === 'add' && rawId === undefined) {\n return problem('field', null, context.allowed ? text.afterIdMissingScoped : text.afterIdMissing)\n }\n if (type === 'add' && rawId === null) {\n if (context.allowed) return problem('scope', null, text.addAtStart)\n }\n else if (typeof rawId !== 'string' || !rawId.trim()) {\n return problem('field', null, text.idMissing(idField))\n }\n const id = typeof rawId === 'string' ? rawId.trim() : null\n if (id !== null) {\n if (!known(id)) return problem('unknown', id, text.unknownId(id))\n if (context.allowed && !context.allowed.has(id)) return problem('scope', id, text.outsideScope(id))\n }\n\n if (type === 'delete') {\n if (edited.has(id!)) return problem('duplicate', id, text.duplicate(id!))\n edited.add(id!)\n return accept({ type, id: id! })\n }\n\n if (type === 'convert') {\n const to = typeof value.to === 'string' ? value.to.trim() : ''\n if (!to) return problem('field', id, text.toMissing)\n if (!context.targets.has(to)) return problem('target', id, text.badTarget(to, [...context.targets].join(', ')))\n if (edited.has(id!)) return problem('duplicate', id, text.duplicate(id!))\n edited.add(id!)\n return accept({ type, id: id!, to })\n }\n\n const markdown = typeof value.markdown === 'string' ? stripBlockLineEcho(value.markdown, known).trim() : ''\n if (!markdown) return problem('field', id, type === 'update' ? text.markdownMissingUpdate : text.markdownMissing)\n if (markdown.length > AGENT_LIMITS.markdown) return problem('field', id, text.markdownTooLong(AGENT_LIMITS.markdown))\n if (type === 'add') return accept({ type, afterId: id, markdown })\n if (edited.has(id!)) return problem('duplicate', id, text.duplicate(id!))\n edited.add(id!)\n accept({ type: 'update', id: id!, markdown })\n })\n\n // An operation on a block inside another operation's block is dropped, naming the outermost operation that covers it.\n const owners = accepted.filter(({ op }) => op.type === 'update' || op.type === 'delete')\n const covering = ({ op }: typeof accepted[number]) => {\n const target = agentOpTarget(op)\n return target === null ? [] : owners.filter(owner => context.lines.below(agentOpTarget(owner.op)!).has(target))\n }\n const valid: ModelAgentOp[] = []\n for (const entry of accepted) {\n const cover = covering(entry)\n const owner = cover.find(candidate => !covering(candidate).length) ?? cover[0]\n if (!owner) {\n valid.push(entry.op)\n continue\n }\n const target = agentOpTarget(entry.op)!\n problems.push({\n index: entry.index,\n type: entry.op.type,\n id: target,\n reason: 'inside',\n detail: text.inside(target, agentOpTarget(owner.op)!, owner.index, owner.op.type === 'delete'),\n })\n }\n problems.sort((a, b) => a.index - b.index)\n return { valid, problems }\n}\n\n/** The problem for a tool call whose input was no object with the list `ops` (index 0), worded in `locale` (default `de`). */\nexport function agentUnreadableProblem({ locale = 'de' }: AgentTextOptions = {}): AgentOpProblem {\n return { index: 0, type: null, id: null, reason: 'field', detail: AGENT_TEXTS[locale].problem.unreadable }\n}\n\n/**\n * Tool result asking the model to call `tool` (default `edit_document`, the host's own tool name when it exposes the\n * operations under another one) again without the invalid operations' mistakes; worded in `locale` (default `de`).\n * By default nothing was applied and the model resends the whole list; with `partial` the host already shows the\n * valid operations, so the model resends only corrected versions of the listed ones.\n */\nexport function agentRetryMessage(\n problems: readonly AgentOpProblem[],\n scoped: boolean,\n { locale = 'de', tool = AGENT_TOOL, partial = false }: AgentTextOptions & { tool?: string, partial?: boolean } = {},\n): string {\n const text = AGENT_TEXTS[locale].retry\n const ids = [...new Set(problems.filter(p => p.reason !== 'inside').map(p => p.id).filter((id): id is string => !!id))]\n return [\n partial ? text.failedPartial : text.failed,\n ...(ids.length ? [text.invalidIds(ids.join(', '))] : []),\n ...problems.map(p => text.operation(p.index, p.type, p.detail)),\n ...(problems.some(p => p.reason === 'inside') ? [text.inside] : []),\n scoped ? text.scoped : text.unscoped,\n partial ? text.againPartial(tool) : text.again(tool),\n ].join('\\n')\n}\n\n/** Tool result of a past `edit_document` call: which operations were shown for review, and how many were dropped; worded in `locale` (default `de`). */\nexport function agentShownMessage(ops: readonly AgentOp[], dropped: number, { locale = 'de' }: AgentTextOptions = {}): string {\n const text = AGENT_TEXTS[locale].shown\n const lines = ops.length\n ? [text.shown(ops.map(op => `${op.op} (${agentOpSummary({ ...op, target: agentOpTarget(op) }, { locale })})`).join(', '))]\n : [text.none]\n if (dropped) lines.push(text.dropped(dropped))\n lines.push(text.decisions)\n return lines.join(' ')\n}\n\n/** „Entscheidungen zu deinen letzten Vorschlägen: op1 (update Block X) abgelehnt; …“ (English with `locale: 'en'`), or '' without feedback. */\nexport function agentFeedbackText(feedback: readonly AgentOpFeedback[], { locale = 'de' }: AgentTextOptions = {}): string {\n if (!feedback.length) return ''\n const outcome = AGENT_TEXTS[locale].outcome\n return AGENT_TEXTS[locale].feedback(feedback.map(f => `${f.op} (${agentOpSummary(f, { locale })}) ${outcome[f.outcome]}`).join('; '))\n}\n"],"mappings":"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"}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* prompt describes all of that. Framework-free and free of ProseMirror: the browser writes the text, the server reads it.
|
|
7
7
|
*
|
|
8
8
|
* A line is `[<block id>] <prefix><text>`. The prefix carries list items (`- `, `1. `), quotes (`> `) and the nesting
|
|
9
|
-
* of a block inside a
|
|
9
|
+
* of a block inside a Typed block or host block (two spaces per level). A Typed block is a header line, its body lines and a
|
|
10
10
|
* closing line `:::` without ID. Code blocks keep their own lines: the first one carries the ID, the others start at
|
|
11
11
|
* the left edge, so their content can look like anything.
|
|
12
12
|
*/
|
|
@@ -16,7 +16,7 @@ export declare const TRUNCATED_LINE = "[…] (Rest des Dokuments gekürzt)";
|
|
|
16
16
|
export declare function blockLine(id: string | null, prefix: string, text: string): string;
|
|
17
17
|
/** `markdown` on one line: hard breaks and wrapped lines would start new "blocks". */
|
|
18
18
|
export declare function singleBlockLine(markdown: string): string;
|
|
19
|
-
/** The prefix of blocks inside the block whose lines carry `prefix` (the body of a
|
|
19
|
+
/** The prefix of blocks inside the block whose lines carry `prefix` (the body of a Typed block or host block). */
|
|
20
20
|
export declare function nestedLinePrefix(prefix: string): string;
|
|
21
21
|
/** The prefix of the blocks of a quote. */
|
|
22
22
|
export declare function quoteLinePrefix(prefix: string): string;
|
|
@@ -24,14 +24,14 @@ export declare function quoteLinePrefix(prefix: string): string;
|
|
|
24
24
|
export declare function listLinePrefix(prefix: string, ordered: boolean, number: number): string;
|
|
25
25
|
/** The prefix of the blocks of a list item after its first: they continue under its marker instead of repeating it. */
|
|
26
26
|
export declare function continuedLinePrefix(prefix: string): string;
|
|
27
|
-
/** One chrome row of a
|
|
27
|
+
/** One chrome row of a Typed block (`## title`, `> description`, `Tags: #a`) without its block marker, on one line. */
|
|
28
28
|
export declare function compositeChromePart(markdown: string): string;
|
|
29
29
|
/**
|
|
30
|
-
* The header text of a
|
|
30
|
+
* The header text of a Typed block: `::: <kind> {meta}` (the meta as JSON only when it has entries), then every non-empty
|
|
31
31
|
* chrome part (title, description, tags) separated by ` | `.
|
|
32
32
|
*/
|
|
33
33
|
export declare function compositeLineHeader(kind: string, meta: unknown, chrome: readonly string[]): string;
|
|
34
|
-
/** The closing line of a
|
|
34
|
+
/** The closing line of a Typed block whose header line is indented by `prefix`: no ID. */
|
|
35
35
|
export declare function compositeLineClose(prefix: string): string;
|
|
36
36
|
/** The block IDs of a document text and which blocks lie inside which. */
|
|
37
37
|
export interface BlockLines {
|
|
@@ -54,7 +54,7 @@ export declare function readBlockLines(text: string): BlockLines;
|
|
|
54
54
|
/**
|
|
55
55
|
* Removes what a model echoes from the document lines into its Markdown: a `[<id>] ` prefix of a known block at the
|
|
56
56
|
* start of a line (not inside a fenced code block of its own Markdown, which keeps lines that look like one), and the
|
|
57
|
-
* indentation all non-blank lines share (lines echoed from a
|
|
57
|
+
* indentation all non-blank lines share (lines echoed from a Typed block's body carry its indent, which would turn deeper
|
|
58
58
|
* nested lines into indented code).
|
|
59
59
|
*/
|
|
60
60
|
export declare function stripBlockLineEcho(markdown: string, known: (id: string) => boolean): string;
|
|
@@ -79,7 +79,7 @@ export declare const BLOCK_LINE_MARKERS: string;
|
|
|
79
79
|
export declare const BLOCK_LINE_LIST_TEXT = "Listenpunkte und Zitate stehen nach der ID mit ihrem Zeichen; jeder Absatz darin hat eine eigene ID.";
|
|
80
80
|
/** What the prompt says about the lines of a host block with block content (a callout). */
|
|
81
81
|
export declare const BLOCK_LINE_HOST_TEXT: string;
|
|
82
|
-
/** What the prompt says about the lines of a
|
|
82
|
+
/** What the prompt says about the lines of a Typed block. */
|
|
83
83
|
export declare const BLOCK_LINE_COMPOSITE_TEXT: string;
|
|
84
84
|
/** What the prompt says about the Markdown of an operation: no echo of the line prefix (`stripBlockLineEcho` removes it when it comes anyway). */
|
|
85
85
|
export declare const BLOCK_LINE_ECHO_TEXT = "„markdown“ enthält nur den neuen Inhalt, ohne Block-ID und ohne das Listen- oder Zitatzeichen der Zeile.";
|