@ecsplico/editor 3.5.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +71 -0
- package/dist/adapters/direct-ai.d.ts +4 -4
- package/dist/adapters/direct-ai.js +2 -2
- package/dist/adapters/direct-ai.js.map +1 -1
- package/dist/adapters/document-state.d.ts +1 -1
- package/dist/adapters/document-state.js.map +1 -1
- package/dist/adapters/forge.d.ts +2 -2
- package/dist/adapters/forge.js.map +1 -1
- package/dist/adapters/nitro.d.ts +11 -3
- package/dist/adapters/nitro.js +3 -1
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +6 -6
- package/dist/adapters/shared.js.map +1 -1
- package/dist/code/CodeSurface.vue.d.ts +3 -3
- package/dist/config/index.d.ts +14 -14
- package/dist/config/index.js +8 -8
- package/dist/config/index.js.map +1 -1
- package/dist/core/backend-types.d.ts +3 -3
- package/dist/core/backend-types.js.map +1 -1
- package/dist/core/backend.d.ts +4 -4
- package/dist/core/backend.js.map +1 -1
- package/dist/core/block-convert.d.ts +1 -1
- package/dist/core/block-convert.js +5 -5
- package/dist/core/block-convert.js.map +1 -1
- package/dist/core/block-transfer.d.ts +8 -4
- package/dist/core/block-transfer.js +23 -14
- package/dist/core/block-transfer.js.map +1 -1
- package/dist/core/capabilities.d.ts +113 -0
- package/dist/core/capabilities.js +155 -0
- package/dist/core/capabilities.js.map +1 -0
- package/dist/core/command-types.d.ts +1 -1
- package/dist/core/context.js.map +1 -1
- package/dist/core/convert.d.ts +5 -5
- package/dist/core/convert.js +5 -5
- package/dist/core/convert.js.map +1 -1
- package/dist/core/core-feature.js +1 -1
- package/dist/core/define-editor.d.ts +2 -2
- package/dist/core/define-editor.js +34 -6
- package/dist/core/define-editor.js.map +1 -1
- package/dist/core/derivation.d.ts +119 -0
- package/dist/core/derivation.js +187 -0
- package/dist/core/derivation.js.map +1 -0
- package/dist/core/derive.d.ts +61 -0
- package/dist/core/derive.js +69 -0
- package/dist/core/derive.js.map +1 -0
- package/dist/core/extension-points.d.ts +16 -0
- package/dist/core/feature-context.d.ts +5 -1
- package/dist/core/feature-context.js +10 -3
- package/dist/core/feature-context.js.map +1 -1
- package/dist/core/feature.d.ts +41 -19
- package/dist/core/feature.js.map +1 -1
- package/dist/core/fences.js +1 -1
- package/dist/core/fences.js.map +1 -1
- package/dist/core/index.d.ts +6 -2
- package/dist/core/index.js +5 -1
- package/dist/core/pipeline.d.ts +14 -5
- package/dist/core/pipeline.js +19 -7
- package/dist/core/pipeline.js.map +1 -1
- package/dist/core/properties.d.ts +22 -0
- package/dist/core/properties.js +17 -0
- package/dist/core/properties.js.map +1 -0
- package/dist/core/schema/block-ids.js +5 -5
- package/dist/core/schema/block-ids.js.map +1 -1
- package/dist/core/schema/index.d.ts +2 -1
- package/dist/core/schema/index.js +2 -1
- package/dist/core/schema/index.js.map +1 -1
- package/dist/core/schema/opaque-fence.d.ts +4 -4
- package/dist/core/schema/opaque-fence.js +7 -7
- package/dist/core/schema/opaque-fence.js.map +1 -1
- package/dist/core/schema/persisted-names.d.ts +58 -0
- package/dist/core/schema/persisted-names.js +96 -0
- package/dist/core/schema/persisted-names.js.map +1 -0
- package/dist/core/toolbar-items.js +1 -1
- package/dist/core/toolbar-items.js.map +1 -1
- package/dist/core/util.js +5 -1
- package/dist/core/util.js.map +1 -1
- package/dist/document/DocumentSurface.vue.d.ts +3 -3
- package/dist/features/ai/agent-ops.js +1 -1
- package/dist/features/ai/ai-review.js +1 -1
- package/dist/features/ai/assistant.d.ts +4 -4
- package/dist/features/ai/assistant.js +1 -1
- package/dist/features/ai/assistant.js.map +1 -1
- package/dist/features/ai/components/AiSelectionMenu.js +1 -1
- package/dist/features/ai/components/AiSelectionMenu.js.map +1 -1
- package/dist/features/ai/components/ModelQuickSwitch.js +7 -7
- package/dist/features/ai/components/ModelQuickSwitch.js.map +1 -1
- package/dist/features/ai/components/ModelQuickSwitch.vue.d.ts +4 -4
- package/dist/features/ai/components/SettingsAiTab.js +8 -8
- package/dist/features/ai/components/SettingsAiTab.js.map +1 -1
- package/dist/features/ai/components/SettingsModelProfiles.js +1 -1
- package/dist/features/ai/components/SettingsModelProfiles.js.map +1 -1
- package/dist/features/ai/document-chat-model.d.ts +2 -2
- package/dist/features/ai/document-chat-model.js +5 -5
- package/dist/features/ai/document-chat-model.js.map +1 -1
- package/dist/features/ai/document-chat.js +2 -2
- package/dist/features/ai/document-chat.js.map +1 -1
- package/dist/features/ai/feature.d.ts +2 -2
- package/dist/features/ai/feature.js +2 -2
- package/dist/features/ai/feature.js.map +1 -1
- package/dist/features/ai/ghost-autocomplete.d.ts +4 -4
- package/dist/features/ai/ghost-autocomplete.js +1 -1
- package/dist/features/ai/ghost-autocomplete.js.map +1 -1
- package/dist/features/ai/index.d.ts +3 -3
- package/dist/features/ai/index.js +2 -2
- package/dist/features/ai/model-profiles.d.ts +9 -9
- package/dist/features/ai/model-profiles.js +13 -13
- package/dist/features/ai/model-profiles.js.map +1 -1
- package/dist/features/ai/protocol/agent-ops.d.ts +2 -2
- package/dist/features/ai/protocol/agent-ops.js +1 -1
- package/dist/features/ai/protocol/agent-ops.js.map +1 -1
- package/dist/features/ai/protocol/block-lines.d.ts +7 -7
- package/dist/features/ai/protocol/block-lines.js +10 -10
- package/dist/features/ai/protocol/block-lines.js.map +1 -1
- package/dist/features/ai/protocol/chat.d.ts +5 -5
- package/dist/features/ai/protocol/chat.js +12 -12
- package/dist/features/ai/protocol/chat.js.map +1 -1
- package/dist/features/ai/protocol/generate.d.ts +1 -1
- package/dist/features/ai/protocol/generate.js +1 -1
- package/dist/features/ai/protocol/generate.js.map +1 -1
- package/dist/features/ai/protocol/index.d.ts +3 -3
- package/dist/features/ai/protocol/index.js +2 -2
- package/dist/features/ai/protocol/models.d.ts +3 -3
- package/dist/features/ai/protocol/models.js +3 -3
- package/dist/features/ai/protocol/models.js.map +1 -1
- package/dist/features/ai/protocol/schemas.d.ts +1 -1
- package/dist/features/ai/protocol/schemas.js +1 -1
- package/dist/features/ai/protocol/schemas.js.map +1 -1
- package/dist/features/ai/protocol/tasks.d.ts +5 -5
- package/dist/features/ai/protocol/tasks.js +12 -12
- package/dist/features/ai/protocol/tasks.js.map +1 -1
- package/dist/features/ai/react/AiSelectionMenu.js.map +1 -1
- package/dist/features/ai/react/ModelQuickSwitch.d.ts +4 -4
- package/dist/features/ai/react/ModelQuickSwitch.js +6 -6
- package/dist/features/ai/react/ModelQuickSwitch.js.map +1 -1
- package/dist/features/ai/react/SettingsAiTab.d.ts +1 -1
- package/dist/features/ai/react/SettingsAiTab.js +8 -8
- package/dist/features/ai/react/SettingsAiTab.js.map +1 -1
- package/dist/features/ai/react/SettingsModelProfiles.d.ts +1 -1
- package/dist/features/ai/react/SettingsModelProfiles.js +1 -1
- package/dist/features/ai/react/SettingsModelProfiles.js.map +1 -1
- package/dist/features/ai/react/use-ai-assistant.d.ts +1 -1
- package/dist/features/ai/react/use-ai-assistant.js +1 -1
- package/dist/features/ai/react/use-ai-assistant.js.map +1 -1
- package/dist/features/ai/react/use-model-profiles.d.ts +5 -5
- package/dist/features/ai/react/use-model-profiles.js +2 -2
- package/dist/features/ai/react/use-model-profiles.js.map +1 -1
- package/dist/features/ai/use-ai-assistant.d.ts +1 -1
- package/dist/features/ai/use-ai-assistant.js +1 -1
- package/dist/features/ai/use-ai-assistant.js.map +1 -1
- package/dist/features/ai/use-model-profiles.d.ts +4 -4
- package/dist/features/ai/use-model-profiles.js +2 -2
- package/dist/features/ai/use-model-profiles.js.map +1 -1
- package/dist/features/block-ui/block-actions.d.ts +8 -4
- package/dist/features/block-ui/block-actions.js +38 -22
- package/dist/features/block-ui/block-actions.js.map +1 -1
- package/dist/features/block-ui/block-target.d.ts +29 -0
- package/dist/features/block-ui/block-target.js +63 -0
- package/dist/features/block-ui/block-target.js.map +1 -0
- package/dist/features/block-ui/components/BlockHandles.js +3 -3
- package/dist/features/block-ui/components/BlockHandles.js.map +1 -1
- package/dist/features/block-ui/components/BlockUi.js +11 -23
- package/dist/features/block-ui/components/BlockUi.js.map +1 -1
- package/dist/features/block-ui/feature.d.ts +3 -2
- package/dist/features/block-ui/feature.js +3 -2
- package/dist/features/block-ui/feature.js.map +1 -1
- package/dist/features/block-ui/handle-geometry.js +12 -23
- package/dist/features/block-ui/handle-geometry.js.map +1 -1
- package/dist/features/block-ui/index.d.ts +2 -1
- package/dist/features/block-ui/index.js +2 -1
- package/dist/features/block-ui/react/BlockHandles.d.ts +1 -1
- package/dist/features/block-ui/react/BlockHandles.js +4 -4
- package/dist/features/block-ui/react/BlockHandles.js.map +1 -1
- package/dist/features/block-ui/react/BlockUi.js +13 -25
- package/dist/features/block-ui/react/BlockUi.js.map +1 -1
- package/dist/features/comments/model.js +1 -1
- package/dist/features/composites/accepted-children.d.ts +5 -4
- package/dist/features/composites/accepted-children.js +26 -26
- package/dist/features/composites/accepted-children.js.map +1 -1
- package/dist/features/composites/ai-brief.d.ts +4 -4
- package/dist/features/composites/ai-brief.js +14 -12
- package/dist/features/composites/ai-brief.js.map +1 -1
- package/dist/features/composites/anchors.d.ts +1 -1
- package/dist/features/composites/anchors.js.map +1 -1
- package/dist/features/composites/baskets.d.ts +1 -1
- package/dist/features/composites/baskets.js.map +1 -1
- package/dist/features/composites/bibliography-command.d.ts +1 -1
- package/dist/features/composites/bibliography-form.js +1 -1
- package/dist/features/composites/bibliography-form.js.map +1 -1
- package/dist/features/composites/bibliography.js.map +1 -1
- package/dist/features/composites/block-types-json.d.ts +38 -0
- package/dist/features/composites/block-types-json.js +122 -0
- package/dist/features/composites/block-types-json.js.map +1 -0
- package/dist/features/composites/block-types.d.ts +119 -0
- package/dist/features/composites/block-types.js +343 -0
- package/dist/features/composites/block-types.js.map +1 -0
- package/dist/features/composites/capabilities.js +109 -0
- package/dist/features/composites/capabilities.js.map +1 -0
- package/dist/features/composites/components/BibliographyEditor.js +5 -5
- package/dist/features/composites/components/BibliographyEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeBasketMenu.js +2 -2
- package/dist/features/composites/components/CompositeBasketMenu.js.map +1 -1
- package/dist/features/composites/components/CompositeChrome.js +18 -8
- package/dist/features/composites/components/CompositeChrome.js.map +1 -1
- package/dist/features/composites/components/CompositeChrome.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeDetails.js +11 -10
- package/dist/features/composites/components/CompositeDetails.js.map +1 -1
- package/dist/features/composites/components/CompositeDetails.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeFieldEditor.js +7 -7
- package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeFieldEditor.vue.d.ts +5 -5
- package/dist/features/composites/components/CompositeInspector.js +136 -113
- package/dist/features/composites/components/CompositeInspector.js.map +1 -1
- package/dist/features/composites/components/CompositeInspector.vue.d.ts +3 -3
- package/dist/features/composites/components/CompositeStatusMenu.js +2 -2
- package/dist/features/composites/components/CompositeStatusMenu.js.map +1 -1
- package/dist/features/composites/components/CompositeSummaryEditor.js +1 -1
- package/dist/features/composites/components/CompositeSummaryEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeSummaryEditor.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeTable.js +2 -2
- package/dist/features/composites/components/CompositeTable.js.map +1 -1
- package/dist/features/composites/components/CompositeTagsEditor.js +1 -1
- package/dist/features/composites/components/CompositeTagsEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeTagsEditor.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeView.js +19 -17
- package/dist/features/composites/components/CompositeView.js.map +1 -1
- package/dist/features/composites/components/DerivationBadge.js +15 -6
- package/dist/features/composites/components/DerivationBadge.js.map +1 -1
- package/dist/features/composites/components/FocusChip.js +1 -1
- package/dist/features/composites/components/FocusChip.js.map +1 -1
- package/dist/features/composites/components/FocusChip.vue.d.ts +1 -1
- package/dist/features/composites/components/ReferenceFieldSelect.js +3 -3
- package/dist/features/composites/components/ReferenceFieldSelect.js.map +1 -1
- package/dist/features/composites/components/ReferenceView.js +1 -1
- package/dist/features/composites/components/ReferenceView.js.map +1 -1
- package/dist/features/composites/components/SettingsEditingTab.js +18 -18
- package/dist/features/composites/components/SettingsEditingTab.js.map +1 -1
- package/dist/features/composites/components/SettingsEditingTab.vue.d.ts +3 -3
- package/dist/features/composites/convert.d.ts +4 -4
- package/dist/features/composites/convert.js +27 -28
- package/dist/features/composites/convert.js.map +1 -1
- package/dist/features/composites/derived-chrome.js +34 -28
- package/dist/features/composites/derived-chrome.js.map +1 -1
- package/dist/features/composites/editing-settings-keys.js +6 -6
- package/dist/features/composites/editing-settings-keys.js.map +1 -1
- package/dist/features/composites/feature.d.ts +10 -10
- package/dist/features/composites/feature.js +58 -46
- package/dist/features/composites/feature.js.map +1 -1
- package/dist/features/composites/fences.d.ts +3 -3
- package/dist/features/composites/fences.js +18 -13
- package/dist/features/composites/fences.js.map +1 -1
- package/dist/features/composites/focus.d.ts +10 -10
- package/dist/features/composites/focus.js +11 -11
- package/dist/features/composites/focus.js.map +1 -1
- package/dist/features/composites/heading-composites.d.ts +5 -5
- package/dist/features/composites/heading-composites.js +13 -16
- package/dist/features/composites/heading-composites.js.map +1 -1
- package/dist/features/composites/index.d.ts +20 -18
- package/dist/features/composites/index.js +9 -7
- package/dist/features/composites/inspector-model.d.ts +45 -22
- package/dist/features/composites/inspector-model.js +53 -14
- package/dist/features/composites/inspector-model.js.map +1 -1
- package/dist/features/composites/legacy.d.ts +5 -4
- package/dist/features/composites/legacy.js +16 -23
- package/dist/features/composites/legacy.js.map +1 -1
- package/dist/features/composites/markdown-export.js +3 -3
- package/dist/features/composites/markdown-export.js.map +1 -1
- package/dist/features/composites/merge.d.ts +8 -7
- package/dist/features/composites/merge.js +39 -12
- package/dist/features/composites/merge.js.map +1 -1
- package/dist/features/composites/meta-display.js +5 -5
- package/dist/features/composites/meta-display.js.map +1 -1
- package/dist/features/composites/meta-keys.d.ts +5 -5
- package/dist/features/composites/meta-keys.js +8 -8
- package/dist/features/composites/meta-keys.js.map +1 -1
- package/dist/features/composites/node-views.d.ts +3 -3
- package/dist/features/composites/node-views.js +2 -2
- package/dist/features/composites/node-views.js.map +1 -1
- package/dist/features/composites/nodes.d.ts +13 -13
- package/dist/features/composites/nodes.js +100 -77
- package/dist/features/composites/nodes.js.map +1 -1
- package/dist/features/composites/outline.d.ts +15 -12
- package/dist/features/composites/outline.js +24 -21
- package/dist/features/composites/outline.js.map +1 -1
- package/dist/features/composites/properties.d.ts +51 -0
- package/dist/features/composites/properties.js +89 -0
- package/dist/features/composites/properties.js.map +1 -0
- package/dist/features/composites/react/BibliographyEditor.js +5 -5
- package/dist/features/composites/react/BibliographyEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeBasketMenu.js +2 -2
- package/dist/features/composites/react/CompositeBasketMenu.js.map +1 -1
- package/dist/features/composites/react/CompositeChrome.d.ts +1 -1
- package/dist/features/composites/react/CompositeChrome.js +15 -6
- package/dist/features/composites/react/CompositeChrome.js.map +1 -1
- package/dist/features/composites/react/CompositeDetails.d.ts +1 -1
- package/dist/features/composites/react/CompositeDetails.js +11 -10
- package/dist/features/composites/react/CompositeDetails.js.map +1 -1
- package/dist/features/composites/react/CompositeFieldEditor.d.ts +5 -5
- package/dist/features/composites/react/CompositeFieldEditor.js +6 -6
- package/dist/features/composites/react/CompositeFieldEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeInspector.d.ts +3 -3
- package/dist/features/composites/react/CompositeInspector.js +142 -128
- package/dist/features/composites/react/CompositeInspector.js.map +1 -1
- package/dist/features/composites/react/CompositeStatusMenu.js +2 -2
- package/dist/features/composites/react/CompositeStatusMenu.js.map +1 -1
- package/dist/features/composites/react/CompositeSummaryEditor.d.ts +1 -1
- package/dist/features/composites/react/CompositeSummaryEditor.js +1 -1
- package/dist/features/composites/react/CompositeSummaryEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeTable.d.ts +1 -1
- package/dist/features/composites/react/CompositeTable.js +3 -3
- package/dist/features/composites/react/CompositeTable.js.map +1 -1
- package/dist/features/composites/react/CompositeTagsEditor.d.ts +1 -1
- package/dist/features/composites/react/CompositeTagsEditor.js +1 -1
- package/dist/features/composites/react/CompositeTagsEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeView.js +17 -15
- package/dist/features/composites/react/CompositeView.js.map +1 -1
- package/dist/features/composites/react/DerivationBadge.js +13 -4
- package/dist/features/composites/react/DerivationBadge.js.map +1 -1
- package/dist/features/composites/react/FocusChip.d.ts +1 -1
- package/dist/features/composites/react/FocusChip.js +1 -1
- package/dist/features/composites/react/FocusChip.js.map +1 -1
- package/dist/features/composites/react/ReferenceFieldSelect.js +3 -3
- package/dist/features/composites/react/ReferenceFieldSelect.js.map +1 -1
- package/dist/features/composites/react/ReferenceView.d.ts +1 -1
- package/dist/features/composites/react/ReferenceView.js +1 -1
- package/dist/features/composites/react/ReferenceView.js.map +1 -1
- package/dist/features/composites/react/SettingsEditingTab.d.ts +4 -4
- package/dist/features/composites/react/SettingsEditingTab.js +20 -20
- package/dist/features/composites/react/SettingsEditingTab.js.map +1 -1
- package/dist/features/composites/react.js +1 -1
- package/dist/features/composites/react.js.map +1 -1
- package/dist/features/composites/reference-ai.js +1 -1
- package/dist/features/composites/reference-ai.js.map +1 -1
- package/dist/features/composites/reference-label.d.ts +3 -3
- package/dist/features/composites/reference-label.js +6 -6
- package/dist/features/composites/reference-label.js.map +1 -1
- package/dist/features/composites/reference-suggestion.d.ts +1 -1
- package/dist/features/composites/reference-suggestion.js +3 -3
- package/dist/features/composites/reference-suggestion.js.map +1 -1
- package/dist/features/composites/reference-text.d.ts +2 -2
- package/dist/features/composites/reference-text.js +4 -4
- package/dist/features/composites/reference-text.js.map +1 -1
- package/dist/features/composites/reference.d.ts +3 -3
- package/dist/features/composites/reference.js +1 -1
- package/dist/features/composites/reference.js.map +1 -1
- package/dist/features/composites/reveal-source.d.ts +3 -3
- package/dist/features/composites/reveal-source.js +6 -6
- package/dist/features/composites/reveal-source.js.map +1 -1
- package/dist/features/composites/rows-model.d.ts +2 -2
- package/dist/features/composites/rows-model.js +4 -3
- package/dist/features/composites/rows-model.js.map +1 -1
- package/dist/features/composites/rows.d.ts +16 -28
- package/dist/features/composites/rows.js +20 -54
- package/dist/features/composites/rows.js.map +1 -1
- package/dist/features/composites/schema.d.ts +12 -11
- package/dist/features/composites/schema.js +10 -9
- package/dist/features/composites/schema.js.map +1 -1
- package/dist/features/composites/source.d.ts +20 -0
- package/dist/features/composites/source.js +40 -0
- package/dist/features/composites/source.js.map +1 -0
- package/dist/features/composites/split.d.ts +11 -11
- package/dist/features/composites/split.js +20 -20
- package/dist/features/composites/split.js.map +1 -1
- package/dist/features/composites/structure-mode.js +3 -3
- package/dist/features/composites/structure-mode.js.map +1 -1
- package/dist/features/composites/table-model.js +2 -2
- package/dist/features/composites/table-model.js.map +1 -1
- package/dist/features/composites/use-composite-inspector.js +3 -1
- package/dist/features/composites/use-composite-inspector.js.map +1 -1
- package/dist/features/composites/use-composite-rows.d.ts +2 -2
- package/dist/features/composites/use-composite-rows.js.map +1 -1
- package/dist/features/composites/vue.js +1 -1
- package/dist/features/composites/vue.js.map +1 -1
- package/dist/features/image-studio/components/ImageStudioDialog.js +1 -1
- package/dist/features/image-studio/components/ImageStudioDialog.js.map +1 -1
- package/dist/features/image-studio/components/ImageStudioDialog.vue.d.ts +1 -1
- package/dist/features/image-studio/components/ImageStudioView.js.map +1 -1
- package/dist/features/image-studio/feature.d.ts +1 -1
- package/dist/features/image-studio/feature.js +1 -1
- package/dist/features/image-studio/feature.js.map +1 -1
- package/dist/features/image-studio/node-core.d.ts +3 -3
- package/dist/features/image-studio/node-core.js +1 -1
- package/dist/features/image-studio/node-core.js.map +1 -1
- package/dist/features/image-studio/node-store.d.ts +1 -1
- package/dist/features/image-studio/node-store.js +1 -1
- package/dist/features/image-studio/node-store.js.map +1 -1
- package/dist/features/image-studio/react/ImageStudioDialog.d.ts +1 -1
- package/dist/features/image-studio/react/ImageStudioDialog.js +1 -1
- package/dist/features/image-studio/react/ImageStudioDialog.js.map +1 -1
- package/dist/features/image-studio/react/ImageStudioView.js +1 -1
- package/dist/features/image-studio/react/ImageStudioView.js.map +1 -1
- package/dist/features/image-studio/react/store.d.ts +3 -3
- package/dist/features/image-studio/react/store.js.map +1 -1
- package/dist/features/image-studio/react.d.ts +1 -1
- package/dist/features/image-studio/react.js +1 -1
- package/dist/features/image-studio/react.js.map +1 -1
- package/dist/features/image-studio/schema.d.ts +1 -1
- package/dist/features/image-studio/schema.js +1 -1
- package/dist/features/image-studio/schema.js.map +1 -1
- package/dist/features/image-studio/state.d.ts +3 -3
- package/dist/features/image-studio/state.js +2 -2
- package/dist/features/image-studio/state.js.map +1 -1
- package/dist/features/image-studio/store.d.ts +3 -3
- package/dist/features/image-studio/vue.d.ts +1 -1
- package/dist/features/image-studio/vue.js +1 -1
- package/dist/features/image-studio/vue.js.map +1 -1
- package/dist/features/media/index.js +1 -1
- package/dist/features/media/react/AudioRecorderModal.js +1 -1
- package/dist/features/media/react.js +1 -1
- package/dist/features/mentions/tag.js +2 -1
- package/dist/features/mentions/tag.js.map +1 -1
- package/dist/features/themes/components/SettingsAppearanceTab.js +1 -1
- package/dist/features/themes/components/SettingsAppearanceTab.js.map +1 -1
- package/dist/features/themes/feature.d.ts +1 -1
- package/dist/features/themes/feature.js.map +1 -1
- package/dist/features/themes/react/SettingsAppearanceTab.d.ts +1 -1
- package/dist/features/themes/react/SettingsAppearanceTab.js +1 -1
- package/dist/features/themes/react/SettingsAppearanceTab.js.map +1 -1
- package/dist/features/themes/theme-runtime.js +1 -1
- package/dist/features/themes/theme-runtime.js.map +1 -1
- package/dist/features/transcript/TranscriptSegmentView.js +1 -1
- package/dist/features/transcript/TranscriptSegmentView.js.map +1 -1
- package/dist/features/transcript/react/TranscriptSegmentView.js +1 -1
- package/dist/features/transcript/react/TranscriptSegmentView.js.map +1 -1
- package/dist/features/transcript/segment-node.js.map +1 -1
- package/dist/features/transfer/feature.js +1 -1
- package/dist/features/transfer/feature.js.map +1 -1
- package/dist/features/transfer/transforms.d.ts +4 -4
- package/dist/features/transfer/transforms.js +12 -12
- package/dist/features/transfer/transforms.js.map +1 -1
- package/dist/i18n/de/ai.js +4 -4
- package/dist/i18n/de/ai.js.map +1 -1
- package/dist/i18n/de/authors.js +1 -1
- package/dist/i18n/de/authors.js.map +1 -1
- package/dist/i18n/de/comments.js +1 -1
- package/dist/i18n/de/comments.js.map +1 -1
- package/dist/i18n/de/composites.js +62 -59
- package/dist/i18n/de/composites.js.map +1 -1
- package/dist/i18n/de/image-studio.js +2 -2
- package/dist/i18n/de/image-studio.js.map +1 -1
- package/dist/i18n/de/integrations.js +20 -20
- package/dist/i18n/de/integrations.js.map +1 -1
- package/dist/i18n/de/markdown.js +1 -1
- package/dist/i18n/de/markdown.js.map +1 -1
- package/dist/i18n/de/palette.js +1 -1
- package/dist/i18n/de/palette.js.map +1 -1
- package/dist/i18n/de/themes.js +3 -3
- package/dist/i18n/de/themes.js.map +1 -1
- package/dist/i18n/de/transfer.js +2 -2
- package/dist/i18n/de/transfer.js.map +1 -1
- package/dist/i18n/de/tree.js +6 -6
- package/dist/i18n/de/tree.js.map +1 -1
- package/dist/i18n/de.d.ts +101 -98
- package/dist/i18n/en/ai.js +2 -2
- package/dist/i18n/en/ai.js.map +1 -1
- package/dist/i18n/en/composites.js +64 -61
- package/dist/i18n/en/composites.js.map +1 -1
- package/dist/i18n/en/integrations.js +9 -9
- package/dist/i18n/en/integrations.js.map +1 -1
- package/dist/i18n/en/markdown.js +1 -1
- package/dist/i18n/en/markdown.js.map +1 -1
- package/dist/i18n/en/palette.js +1 -1
- package/dist/i18n/en/palette.js.map +1 -1
- package/dist/i18n/en/themes.js +4 -4
- package/dist/i18n/en/themes.js.map +1 -1
- package/dist/i18n/en/tree.js +5 -5
- package/dist/i18n/en/tree.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/integrations/composite-ai/bibliography-fetch.d.ts +6 -6
- package/dist/integrations/composite-ai/bibliography-fetch.js +19 -19
- package/dist/integrations/composite-ai/bibliography-fetch.js.map +1 -1
- package/dist/integrations/composite-ai/composite-fill.d.ts +4 -4
- package/dist/integrations/composite-ai/composite-fill.js +5 -5
- package/dist/integrations/composite-ai/composite-fill.js.map +1 -1
- package/dist/integrations/composite-ai/composite-summary.d.ts +2 -2
- package/dist/integrations/composite-ai/composite-summary.js +5 -5
- package/dist/integrations/composite-ai/composite-summary.js.map +1 -1
- package/dist/integrations/composite-ai/derive.d.ts +17 -17
- package/dist/integrations/composite-ai/derive.js +27 -26
- package/dist/integrations/composite-ai/derive.js.map +1 -1
- package/dist/integrations/composite-ai/index.d.ts +14 -15
- package/dist/integrations/composite-ai/index.js +98 -77
- package/dist/integrations/composite-ai/index.js.map +1 -1
- package/dist/integrations/composite-ai/outline-sanitize.d.ts +1 -1
- package/dist/integrations/composite-ai/outline-sanitize.js +1 -1
- package/dist/integrations/composite-ai/outline-sanitize.js.map +1 -1
- package/dist/integrations/composite-ai/rendition.d.ts +9 -9
- package/dist/integrations/composite-ai/rendition.js +27 -27
- package/dist/integrations/composite-ai/rendition.js.map +1 -1
- package/dist/integrations/composite-ai/split.d.ts +8 -8
- package/dist/integrations/composite-ai/split.js +12 -12
- package/dist/integrations/composite-ai/split.js.map +1 -1
- package/dist/integrations/composite-ai/transfer-transforms.d.ts +2 -2
- package/dist/integrations/composite-ai/transfer-transforms.js +12 -12
- package/dist/integrations/composite-ai/transfer-transforms.js.map +1 -1
- package/dist/integrations/composite-media/index.d.ts +4 -3
- package/dist/integrations/composite-media/index.js +20 -14
- package/dist/integrations/composite-media/index.js.map +1 -1
- package/dist/markdown/MarkdownSurface.vue.d.ts +7 -7
- package/dist/markdown/document.js +1 -1
- package/dist/markdown/document.js.map +1 -1
- package/dist/nuxt/module.d.ts +30 -24
- package/dist/nuxt/module.js.map +1 -1
- package/dist/nuxt/runtime/server/plugins/editor-server.js +3 -2
- package/dist/nuxt/runtime/server/plugins/editor-server.js.map +1 -1
- package/dist/presets/compose.d.ts +6 -6
- package/dist/presets/compose.js +8 -5
- package/dist/presets/compose.js.map +1 -1
- package/dist/react/AdvancedEditor.d.ts +2 -2
- package/dist/react/AdvancedEditor.js +1 -1
- package/dist/react/AdvancedEditor.js.map +1 -1
- package/dist/react/compose.d.ts +1 -1
- package/dist/react/compose.js +2 -2
- package/dist/react/compose.js.map +1 -1
- package/dist/react/composed-surface.d.ts +5 -5
- package/dist/react/composed-surface.js +2 -2
- package/dist/react/composed-surface.js.map +1 -1
- package/dist/server/ai.d.ts +7 -7
- package/dist/server/ai.js +1 -1
- package/dist/server/ai.js.map +1 -1
- package/dist/server/auth.d.ts +1 -1
- package/dist/server/collab-state.d.ts +1 -1
- package/dist/server/collab-state.js.map +1 -1
- package/dist/server/collab.d.ts +4 -4
- package/dist/server/collab.js +22 -17
- package/dist/server/collab.js.map +1 -1
- package/dist/server/handlers/ai.d.ts +9 -6
- package/dist/server/handlers/ai.js +13 -17
- package/dist/server/handlers/ai.js.map +1 -1
- package/dist/server/handlers/context.d.ts +4 -0
- package/dist/server/handlers/context.js.map +1 -1
- package/dist/server/handlers/editor.d.ts +33 -32
- package/dist/server/handlers/editor.js +13 -8
- package/dist/server/handlers/editor.js.map +1 -1
- package/dist/server/handlers/images.d.ts +1 -1
- package/dist/server/handlers/images.js +1 -1
- package/dist/server/handlers/images.js.map +1 -1
- package/dist/server/host.d.ts +4 -0
- package/dist/server/host.js +10 -2
- package/dist/server/host.js.map +1 -1
- package/dist/server/index.d.ts +3 -3
- package/dist/server/ports.d.ts +8 -8
- package/dist/server/ports.js.map +1 -1
- package/dist/settings/index.d.ts +20 -19
- package/dist/settings/index.js +25 -24
- package/dist/settings/index.js.map +1 -1
- package/dist/settings/migrate.d.ts +18 -0
- package/dist/settings/migrate.js +46 -0
- package/dist/settings/migrate.js.map +1 -0
- package/dist/settings/values.d.ts +12 -12
- package/dist/settings/values.js +11 -11
- package/dist/settings/values.js.map +1 -1
- package/dist/styles/composites.css +10 -10
- package/dist/tree/DocumentTree.js +12 -5
- package/dist/tree/DocumentTree.js.map +1 -1
- package/dist/tree/drop-rules.js +5 -5
- package/dist/tree/drop-rules.js.map +1 -1
- package/dist/tree/react/DocumentTree.js +14 -5
- package/dist/tree/react/DocumentTree.js.map +1 -1
- package/dist/tree/tree-host.js +6 -6
- package/dist/tree/tree-host.js.map +1 -1
- package/dist/tree/tree-items.js +34 -28
- package/dist/tree/tree-items.js.map +1 -1
- package/dist/tree/tree-model.js +16 -16
- package/dist/tree/tree-model.js.map +1 -1
- package/dist/tree/tree-rows.js +2 -2
- package/dist/tree/tree-rows.js.map +1 -1
- package/dist/tree/tree-view-model.d.ts +2 -2
- package/dist/tree/tree-view-model.js.map +1 -1
- package/dist/vue/AdvancedEditor.js +2 -2
- package/dist/vue/AdvancedEditor.js.map +1 -1
- package/dist/vue/AdvancedEditor.vue.d.ts +10 -10
- package/dist/vue/SimpleEditor.vue.d.ts +4 -4
- package/dist/vue/components/EditorSurface.vue.d.ts +4 -4
- package/dist/vue/compose.d.ts +1 -1
- package/dist/vue/compose.js +2 -2
- package/dist/vue/compose.js.map +1 -1
- package/package.json +1 -1
- package/dist/features/composites/derivation.d.ts +0 -62
- package/dist/features/composites/derivation.js +0 -102
- package/dist/features/composites/derivation.js.map +0 -1
- package/dist/features/composites/kinds.d.ts +0 -83
- package/dist/features/composites/kinds.js +0 -285
- package/dist/features/composites/kinds.js.map +0 -1
|
@@ -6,11 +6,11 @@
|
|
|
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
|
*/
|
|
13
|
-
/** One level of nesting inside a
|
|
13
|
+
/** One level of nesting inside a Typed block or host block. */
|
|
14
14
|
const INDENT = " ";
|
|
15
15
|
/** The line shown instead of the rest of a document that did not fit. */
|
|
16
16
|
const TRUNCATED_LINE = "[…] (Rest des Dokuments gekürzt)";
|
|
@@ -22,7 +22,7 @@ function blockLine(id, prefix, text) {
|
|
|
22
22
|
function singleBlockLine(markdown) {
|
|
23
23
|
return markdown.replace(/\s*\n\s*/g, " ");
|
|
24
24
|
}
|
|
25
|
-
/** The prefix of blocks inside the block whose lines carry `prefix` (the body of a
|
|
25
|
+
/** The prefix of blocks inside the block whose lines carry `prefix` (the body of a Typed block or host block). */
|
|
26
26
|
function nestedLinePrefix(prefix) {
|
|
27
27
|
return `${prefix}${INDENT}`;
|
|
28
28
|
}
|
|
@@ -38,18 +38,18 @@ function listLinePrefix(prefix, ordered, number) {
|
|
|
38
38
|
function continuedLinePrefix(prefix) {
|
|
39
39
|
return prefix.replace(/(?:- |\d+\. )$/, (marker) => " ".repeat(marker.length));
|
|
40
40
|
}
|
|
41
|
-
/** One chrome row of a
|
|
41
|
+
/** One chrome row of a Typed block (`## title`, `> description`, `Tags: #a`) without its block marker, on one line. */
|
|
42
42
|
function compositeChromePart(markdown) {
|
|
43
43
|
return singleBlockLine(markdown.replace(/^(?:#+|>) ?/, ""));
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
|
-
* The header text of a
|
|
46
|
+
* The header text of a Typed block: `::: <kind> {meta}` (the meta as JSON only when it has entries), then every non-empty
|
|
47
47
|
* chrome part (title, description, tags) separated by ` | `.
|
|
48
48
|
*/
|
|
49
49
|
function compositeLineHeader(kind, meta, chrome) {
|
|
50
50
|
return [`::: ${kind}${meta && typeof meta === "object" && Object.keys(meta).length ? ` ${JSON.stringify(meta)}` : ""}`, ...chrome.filter(Boolean)].join(" | ");
|
|
51
51
|
}
|
|
52
|
-
/** The closing line of a
|
|
52
|
+
/** The closing line of a Typed block whose header line is indented by `prefix`: no ID. */
|
|
53
53
|
function compositeLineClose(prefix) {
|
|
54
54
|
return `${nestedLinePrefix(prefix)}:::`;
|
|
55
55
|
}
|
|
@@ -120,7 +120,7 @@ function readBlockLines(text) {
|
|
|
120
120
|
/**
|
|
121
121
|
* Removes what a model echoes from the document lines into its Markdown: a `[<id>] ` prefix of a known block at the
|
|
122
122
|
* start of a line (not inside a fenced code block of its own Markdown, which keeps lines that look like one), and the
|
|
123
|
-
* indentation all non-blank lines share (lines echoed from a
|
|
123
|
+
* indentation all non-blank lines share (lines echoed from a Typed block's body carry its indent, which would turn deeper
|
|
124
124
|
* nested lines into indented code).
|
|
125
125
|
*/
|
|
126
126
|
function stripBlockLineEcho(markdown, known) {
|
|
@@ -161,12 +161,12 @@ const BLOCK_LINE_MARKERS = `Aufzählung („${listLinePrefix("", false, 1)}“),
|
|
|
161
161
|
const BLOCK_LINE_LIST_TEXT = "Listenpunkte und Zitate stehen nach der ID mit ihrem Zeichen; jeder Absatz darin hat eine eigene ID.";
|
|
162
162
|
/** What the prompt says about the lines of a host block with block content (a callout). */
|
|
163
163
|
const BLOCK_LINE_HOST_TEXT = `Im Dokument beginnt ein eigener Block mit Inhaltsblöcken mit der Zeile „${blockLine("ID", "", "<erste Zeile seiner Markdown-Form>")}“; seine Inhaltsblöcke folgen als eigene Zeilen mit IDs, um zwei Leerzeichen eingerückt.`;
|
|
164
|
-
/** What the prompt says about the lines of a
|
|
165
|
-
const BLOCK_LINE_COMPOSITE_TEXT = `Im Dokument beginnt ein
|
|
164
|
+
/** What the prompt says about the lines of a Typed block. */
|
|
165
|
+
const BLOCK_LINE_COMPOSITE_TEXT = `Im Dokument beginnt ein typisierter Block mit der Kopfzeile „${blockLine("ID", "", compositeLineHeader("Blocktyp", { feld: "wert" }, [
|
|
166
166
|
"Titel",
|
|
167
167
|
"Beschreibung",
|
|
168
168
|
"Tags: #a #b"
|
|
169
|
-
]))}“ (die Felder als JSON nur, wenn welche gesetzt sind; leere Teile fehlen samt ihrem „|“). Seine Inhaltsblöcke folgen als eigene Zeilen mit ihren IDs, um zwei Leerzeichen eingerückt; eine Zeile „${compositeLineClose("")}“ ohne ID schließt ihn. Das Feld „bib“ ist eine Literaturangabe als CSL-JSON, „derivation“ beschreibt, woraus der
|
|
169
|
+
]))}“ (die Felder als JSON nur, wenn welche gesetzt sind; leere Teile fehlen samt ihrem „|“). Seine Inhaltsblöcke folgen als eigene Zeilen mit ihren IDs, um zwei Leerzeichen eingerückt; eine Zeile „${compositeLineClose("")}“ ohne ID schließt ihn. Das Feld „bib“ ist eine Literaturangabe als CSL-JSON, „derivation“ beschreibt, woraus der Block erzeugt wurde. Ein Verweis auf einen Block des Dokuments steht im Text als „[@<Block-ID>]“, mit Fundstelle als „[@<Block-ID>, S. 12]“.`;
|
|
170
170
|
/** What the prompt says about the Markdown of an operation: no echo of the line prefix (`stripBlockLineEcho` removes it when it comes anyway). */
|
|
171
171
|
const BLOCK_LINE_ECHO_TEXT = "„markdown“ enthält nur den neuen Inhalt, ohne Block-ID und ohne das Listen- oder Zitatzeichen der Zeile.";
|
|
172
172
|
/** What the retry message says about IDs. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-lines.js","names":[],"sources":["../../../../src/features/ai/protocol/block-lines.ts"],"sourcesContent":["// i18n-ignore-file: the document lines and the prompt texts describing them are model-facing (German; the model's language is not the editor's)\n/**\n * The line format of the document as the chat model sees it, in one place: how the lines are written (the primitives\n * `documentChatText` formats its lines with), how they are read back (the block IDs of a text and which blocks lie\n * inside which, ignoring fenced code), how an echoed line prefix is removed from the model's Markdown, and how the\n * prompt describes all of that. Framework-free and free of ProseMirror: the browser writes the text, the server reads it.\n *\n * A line is `[<block id>] <prefix><text>`. The prefix carries list items (`- `, `1. `), quotes (`> `) and the nesting\n * of a block inside a Baustein or host block (two spaces per level). A Baustein is a header line, its body lines and a\n * closing line `:::` without ID. Code blocks keep their own lines: the first one carries the ID, the others start at\n * the left edge, so their content can look like anything.\n */\n\n// ---------- Writing ----------------------------------------------------------\n\n/** One level of nesting inside a Baustein or host block. */\nconst INDENT = ' '\n\n/** The line shown instead of the rest of a document that did not fit. */\nexport const TRUNCATED_LINE = '[…] (Rest des Dokuments gekürzt)'\n\n/** A line of block `id` (none: an ID-less line), indented by `prefix`, holding `text`. */\nexport function blockLine(id: string | null, prefix: string, text: string): string {\n return `${id ? `[${id}] ` : ''}${prefix}${text}`\n}\n\n/** `markdown` on one line: hard breaks and wrapped lines would start new \"blocks\". */\nexport function singleBlockLine(markdown: string): string {\n return markdown.replace(/\\s*\\n\\s*/g, ' ')\n}\n\n/** The prefix of blocks inside the block whose lines carry `prefix` (the body of a Baustein or host block). */\nexport function nestedLinePrefix(prefix: string): string {\n return `${prefix}${INDENT}`\n}\n\n/** The prefix of the blocks of a quote. */\nexport function quoteLinePrefix(prefix: string): string {\n return `${prefix}> `\n}\n\n/** The prefix of the blocks of list item `number` (1-based; ignored in a bullet list). */\nexport function listLinePrefix(prefix: string, ordered: boolean, number: number): string {\n return `${prefix}${ordered ? `${number}. ` : '- '}`\n}\n\n/** The prefix of the blocks of a list item after its first: they continue under its marker instead of repeating it. */\nexport function continuedLinePrefix(prefix: string): string {\n return prefix.replace(/(?:- |\\d+\\. )$/, marker => ' '.repeat(marker.length))\n}\n\n/** One chrome row of a Baustein (`## title`, `> description`, `Tags: #a`) without its block marker, on one line. */\nexport function compositeChromePart(markdown: string): string {\n return singleBlockLine(markdown.replace(/^(?:#+|>) ?/, ''))\n}\n\n/**\n * The header text of a Baustein: `::: <kind> {meta}` (the meta as JSON only when it has entries), then every non-empty\n * chrome part (title, description, tags) separated by ` | `.\n */\nexport function compositeLineHeader(kind: string, meta: unknown, chrome: readonly string[]): string {\n const fields = meta && typeof meta === 'object' && Object.keys(meta).length ? ` ${JSON.stringify(meta)}` : ''\n return [`::: ${kind}${fields}`, ...chrome.filter(Boolean)].join(' | ')\n}\n\n/** The closing line of a Baustein whose header line is indented by `prefix`: no ID. */\nexport function compositeLineClose(prefix: string): string {\n return `${nestedLinePrefix(prefix)}:::`\n}\n\n// ---------- Reading ----------------------------------------------------------\n\n/** The block IDs of a document text and which blocks lie inside which. */\nexport interface BlockLines {\n /** Every block ID that starts a line (lines inside fenced code do not count). */\n ids: ReadonlySet<string>\n /** The IDs of all blocks nested below block `id`: the lines indented under its header line (empty for a block without nested blocks). */\n below: (id: string) => ReadonlySet<string>\n}\n\nconst ID_PREFIX = /^\\[([^\\]\\s]+)\\] /\n/** An opening code fence after optional list/quote markers and indentation: three or more backticks, no backtick in the info string. */\nconst FENCE_OPEN = /^(?:[ \\t]|>|[-*+][ \\t]|\\d+[.)][ \\t])*(`{3,})[^`]*$/\nconst FENCE_CLOSE = /^[ \\t]*(`{3,})[ \\t]*$/\n/** Indentation and list/quote markers at the start of a line's content. */\nconst LINE_PREFIX = /^(?:[ \\t]|>|[-*+][ \\t]|\\d+[.)][ \\t])*/\n\n/**\n * The fence length after `line` when a fence of `fence` backticks was open before it (0: none). A line of at least as\n * many backticks closes the fence; `opens` says whether a line outside a fence may open one.\n */\nfunction fenceAfter(fence: number, line: string, opens: boolean): number {\n if (fence) {\n const closing = FENCE_CLOSE.exec(line)\n return closing && closing[1]!.length >= fence ? 0 : fence\n }\n const opening = opens ? FENCE_OPEN.exec(line) : null\n return opening ? opening[1]!.length : 0\n}\n\nconst NOTHING: ReadonlySet<string> = new Set()\n\n/**\n * Reads the lines of `text` (as `documentChatText` writes them). Lines inside a fenced code block are code, never\n * block lines, so a code line like `[ghost] text` does not become an ID; only a line that carries an ID opens a fence\n * (a stray line of backticks inside the code cannot swallow what follows).\n *\n * Nesting follows the indentation: the blocks on the lines under a header line that are indented further belong to its\n * block. Lines of list items (their marker, and what continues under it) never head a block of their own: a paragraph\n * and its nested list are siblings, nothing lies \"inside\" the paragraph. A block without lines of its own (a list, a\n * quote) has no nested blocks; a block's own ID on a nested line (a child without an ID of its own) is not \"inside\".\n */\nexport function readBlockLines(text: string): BlockLines {\n const ids = new Set<string>()\n const nested = new Map<string, Set<string>>()\n // The blocks whose lines enclose the current one, outermost first; `head`: the block can have nested blocks.\n const open: { id: string, indent: number, head: boolean }[] = []\n let fence = 0\n\n for (const line of text.split('\\n')) {\n const id = ID_PREFIX.exec(line)?.[1]\n if (fence) {\n fence = fenceAfter(fence, line, false)\n continue\n }\n // The truncation notice reads like a line with the ID `…`.\n if (!id || line === TRUNCATED_LINE) continue\n const content = line.slice(id.length + 3)\n fence = fenceAfter(0, content, true)\n ids.add(id)\n\n const indent = /^[ \\t]*/.exec(content)![0].length\n const listItem = /[-*+\\d]/.test(LINE_PREFIX.exec(content)![0])\n while (open.length && open.at(-1)!.indent >= indent) open.pop()\n for (const outer of open) {\n if (!outer.head || outer.id === id) continue\n const inside = nested.get(outer.id)\n if (inside) inside.add(id)\n else nested.set(outer.id, new Set([id]))\n }\n open.push({ id, indent, head: !listItem && (open.at(-1)?.head ?? true) })\n }\n return { ids, below: id => nested.get(id) ?? NOTHING }\n}\n\n/**\n * Removes what a model echoes from the document lines into its Markdown: a `[<id>] ` prefix of a known block at the\n * start of a line (not inside a fenced code block of its own Markdown, which keeps lines that look like one), and the\n * indentation all non-blank lines share (lines echoed from a Baustein's body carry its indent, which would turn deeper\n * nested lines into indented code).\n */\nexport function stripBlockLineEcho(markdown: string, known: (id: string) => boolean): string {\n let fence = 0\n const stripped = markdown.split('\\n').map((line) => {\n if (fence) {\n fence = fenceAfter(fence, line, false)\n return line\n }\n const bare = line.replace(/^\\[([^\\]\\s]+)\\] ?/, (prefix, id: string) => known(id) ? '' : prefix)\n fence = fenceAfter(0, bare, true)\n return bare\n })\n const indents = stripped.filter(line => line.trim()).map(line => /^[ \\t]*/.exec(line)![0].length)\n const common = indents.length ? Math.min(...indents) : 0\n return (common ? stripped.map(line => line.replace(new RegExp(`^[ \\\\t]{0,${common}}`), '')) : stripped).join('\\n')\n}\n\n/**\n * Removes the list and quote markers (`- `, `1. `, `> `) a model echoes from the lines of list items and quotes at the\n * start of each line of its Markdown.\n */\nexport function stripListMarkerEcho(markdown: string): string {\n return markdown.replace(/^(?:[ \\t]*(?:[-*+]|\\d+[.)])[ \\t]+|[ \\t]*>[ \\t]?)+/gm, '')\n}\n\n// ---------- Prompt -----------------------------------------------------------\n\n/** The block ID of the prompt's example line (also the target of its citation example). */\nexport const BLOCK_LINE_EXAMPLE_ID = '0f3c9a52-7d1e-4b8a-9c2f-5e6d7a8b9c0d'\n\n/** The text of the prompt's example line: a speaker line. */\nexport const BLOCK_LINE_EXAMPLE_TEXT = '**Anna:** Wir starten im Mai.'\n\n/** The example line of the prompt, written by `blockLine` like every line of the document. */\nexport const BLOCK_LINE_EXAMPLE = blockLine(BLOCK_LINE_EXAMPLE_ID, '', BLOCK_LINE_EXAMPLE_TEXT)\n\n/** The label of the document in the user message. */\nexport const BLOCK_LINES_LABEL = 'Dokument (aktueller Stand, eine Zeile pro Block, beginnend mit der Block-ID)'\n\n/** What the first lines of the system prompt say about the document's lines. */\nexport const BLOCK_LINE_INTRO = `Jede Zeile des Dokuments beginnt mit der ID ihres Blocks in eckigen Klammern, z. B. \\`${BLOCK_LINE_EXAMPLE}\\`. Redebeiträge beginnen nach der ID mit dem fett gesetzten Namen der Sprecherin bzw. des Sprechers und einem Doppelpunkt.`\n\n/** The list and quote blocks with the characters their lines carry. */\nexport const BLOCK_LINE_MARKERS = `Aufzählung („${listLinePrefix('', false, 1)}“), nummerierte Liste („${listLinePrefix('', true, 1)}“), Zitat („${quoteLinePrefix('')}“)`\n\n/** What the prompt says about lists and quotes in the document. */\nexport const BLOCK_LINE_LIST_TEXT = 'Listenpunkte und Zitate stehen nach der ID mit ihrem Zeichen; jeder Absatz darin hat eine eigene ID.'\n\n/** What the prompt says about the lines of a host block with block content (a callout). */\nexport const BLOCK_LINE_HOST_TEXT = `Im Dokument beginnt ein eigener Block mit Inhaltsblöcken mit der Zeile „${blockLine('ID', '', '<erste Zeile seiner Markdown-Form>')}“; seine Inhaltsblöcke folgen als eigene Zeilen mit IDs, um zwei Leerzeichen eingerückt.`\n\n/** What the prompt says about the lines of a Baustein. */\nexport const BLOCK_LINE_COMPOSITE_TEXT = `Im Dokument beginnt ein Baustein mit der Kopfzeile „${blockLine('ID', '', compositeLineHeader('Art', { feld: 'wert' }, ['Titel', 'Beschreibung', 'Tags: #a #b']))}“ (die Felder als JSON nur, wenn welche gesetzt sind; leere Teile fehlen samt ihrem „|“). Seine Inhaltsblöcke folgen als eigene Zeilen mit ihren IDs, um zwei Leerzeichen eingerückt; eine Zeile „${compositeLineClose('')}“ ohne ID schließt ihn. Das Feld „bib“ ist eine Literaturangabe als CSL-JSON, „derivation“ beschreibt, woraus der Baustein erzeugt wurde. Ein Verweis auf einen Baustein des Dokuments steht im Text als „[@<Block-ID>]“, mit Fundstelle als „[@<Block-ID>, S. 12]“.`\n\n/** What the prompt says about the Markdown of an operation: no echo of the line prefix (`stripBlockLineEcho` removes it when it comes anyway). */\nexport const BLOCK_LINE_ECHO_TEXT = '„markdown“ enthält nur den neuen Inhalt, ohne Block-ID und ohne das Listen- oder Zitatzeichen der Zeile.'\n\n/** What the retry message says about IDs. */\nexport const BLOCK_LINE_IDS_HINT = 'Verwende nur IDs, die im Dokument in eckigen Klammern stehen; erfinde keine IDs.'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"block-lines.js","names":[],"sources":["../../../../src/features/ai/protocol/block-lines.ts"],"sourcesContent":["// i18n-ignore-file: the document lines and the prompt texts describing them are model-facing (German; the model's language is not the editor's)\n/**\n * The line format of the document as the chat model sees it, in one place: how the lines are written (the primitives\n * `documentChatText` formats its lines with), how they are read back (the block IDs of a text and which blocks lie\n * inside which, ignoring fenced code), how an echoed line prefix is removed from the model's Markdown, and how the\n * prompt describes all of that. Framework-free and free of ProseMirror: the browser writes the text, the server reads it.\n *\n * A line is `[<block id>] <prefix><text>`. The prefix carries list items (`- `, `1. `), quotes (`> `) and the nesting\n * 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\n * closing line `:::` without ID. Code blocks keep their own lines: the first one carries the ID, the others start at\n * the left edge, so their content can look like anything.\n */\n\n// ---------- Writing ----------------------------------------------------------\n\n/** One level of nesting inside a Typed block or host block. */\nconst INDENT = ' '\n\n/** The line shown instead of the rest of a document that did not fit. */\nexport const TRUNCATED_LINE = '[…] (Rest des Dokuments gekürzt)'\n\n/** A line of block `id` (none: an ID-less line), indented by `prefix`, holding `text`. */\nexport function blockLine(id: string | null, prefix: string, text: string): string {\n return `${id ? `[${id}] ` : ''}${prefix}${text}`\n}\n\n/** `markdown` on one line: hard breaks and wrapped lines would start new \"blocks\". */\nexport function singleBlockLine(markdown: string): string {\n return markdown.replace(/\\s*\\n\\s*/g, ' ')\n}\n\n/** The prefix of blocks inside the block whose lines carry `prefix` (the body of a Typed block or host block). */\nexport function nestedLinePrefix(prefix: string): string {\n return `${prefix}${INDENT}`\n}\n\n/** The prefix of the blocks of a quote. */\nexport function quoteLinePrefix(prefix: string): string {\n return `${prefix}> `\n}\n\n/** The prefix of the blocks of list item `number` (1-based; ignored in a bullet list). */\nexport function listLinePrefix(prefix: string, ordered: boolean, number: number): string {\n return `${prefix}${ordered ? `${number}. ` : '- '}`\n}\n\n/** The prefix of the blocks of a list item after its first: they continue under its marker instead of repeating it. */\nexport function continuedLinePrefix(prefix: string): string {\n return prefix.replace(/(?:- |\\d+\\. )$/, marker => ' '.repeat(marker.length))\n}\n\n/** One chrome row of a Typed block (`## title`, `> description`, `Tags: #a`) without its block marker, on one line. */\nexport function compositeChromePart(markdown: string): string {\n return singleBlockLine(markdown.replace(/^(?:#+|>) ?/, ''))\n}\n\n/**\n * The header text of a Typed block: `::: <kind> {meta}` (the meta as JSON only when it has entries), then every non-empty\n * chrome part (title, description, tags) separated by ` | `.\n */\nexport function compositeLineHeader(kind: string, meta: unknown, chrome: readonly string[]): string {\n const fields = meta && typeof meta === 'object' && Object.keys(meta).length ? ` ${JSON.stringify(meta)}` : ''\n return [`::: ${kind}${fields}`, ...chrome.filter(Boolean)].join(' | ')\n}\n\n/** The closing line of a Typed block whose header line is indented by `prefix`: no ID. */\nexport function compositeLineClose(prefix: string): string {\n return `${nestedLinePrefix(prefix)}:::`\n}\n\n// ---------- Reading ----------------------------------------------------------\n\n/** The block IDs of a document text and which blocks lie inside which. */\nexport interface BlockLines {\n /** Every block ID that starts a line (lines inside fenced code do not count). */\n ids: ReadonlySet<string>\n /** The IDs of all blocks nested below block `id`: the lines indented under its header line (empty for a block without nested blocks). */\n below: (id: string) => ReadonlySet<string>\n}\n\nconst ID_PREFIX = /^\\[([^\\]\\s]+)\\] /\n/** An opening code fence after optional list/quote markers and indentation: three or more backticks, no backtick in the info string. */\nconst FENCE_OPEN = /^(?:[ \\t]|>|[-*+][ \\t]|\\d+[.)][ \\t])*(`{3,})[^`]*$/\nconst FENCE_CLOSE = /^[ \\t]*(`{3,})[ \\t]*$/\n/** Indentation and list/quote markers at the start of a line's content. */\nconst LINE_PREFIX = /^(?:[ \\t]|>|[-*+][ \\t]|\\d+[.)][ \\t])*/\n\n/**\n * The fence length after `line` when a fence of `fence` backticks was open before it (0: none). A line of at least as\n * many backticks closes the fence; `opens` says whether a line outside a fence may open one.\n */\nfunction fenceAfter(fence: number, line: string, opens: boolean): number {\n if (fence) {\n const closing = FENCE_CLOSE.exec(line)\n return closing && closing[1]!.length >= fence ? 0 : fence\n }\n const opening = opens ? FENCE_OPEN.exec(line) : null\n return opening ? opening[1]!.length : 0\n}\n\nconst NOTHING: ReadonlySet<string> = new Set()\n\n/**\n * Reads the lines of `text` (as `documentChatText` writes them). Lines inside a fenced code block are code, never\n * block lines, so a code line like `[ghost] text` does not become an ID; only a line that carries an ID opens a fence\n * (a stray line of backticks inside the code cannot swallow what follows).\n *\n * Nesting follows the indentation: the blocks on the lines under a header line that are indented further belong to its\n * block. Lines of list items (their marker, and what continues under it) never head a block of their own: a paragraph\n * and its nested list are siblings, nothing lies \"inside\" the paragraph. A block without lines of its own (a list, a\n * quote) has no nested blocks; a block's own ID on a nested line (a child without an ID of its own) is not \"inside\".\n */\nexport function readBlockLines(text: string): BlockLines {\n const ids = new Set<string>()\n const nested = new Map<string, Set<string>>()\n // The blocks whose lines enclose the current one, outermost first; `head`: the block can have nested blocks.\n const open: { id: string, indent: number, head: boolean }[] = []\n let fence = 0\n\n for (const line of text.split('\\n')) {\n const id = ID_PREFIX.exec(line)?.[1]\n if (fence) {\n fence = fenceAfter(fence, line, false)\n continue\n }\n // The truncation notice reads like a line with the ID `…`.\n if (!id || line === TRUNCATED_LINE) continue\n const content = line.slice(id.length + 3)\n fence = fenceAfter(0, content, true)\n ids.add(id)\n\n const indent = /^[ \\t]*/.exec(content)![0].length\n const listItem = /[-*+\\d]/.test(LINE_PREFIX.exec(content)![0])\n while (open.length && open.at(-1)!.indent >= indent) open.pop()\n for (const outer of open) {\n if (!outer.head || outer.id === id) continue\n const inside = nested.get(outer.id)\n if (inside) inside.add(id)\n else nested.set(outer.id, new Set([id]))\n }\n open.push({ id, indent, head: !listItem && (open.at(-1)?.head ?? true) })\n }\n return { ids, below: id => nested.get(id) ?? NOTHING }\n}\n\n/**\n * Removes what a model echoes from the document lines into its Markdown: a `[<id>] ` prefix of a known block at the\n * start of a line (not inside a fenced code block of its own Markdown, which keeps lines that look like one), and the\n * indentation all non-blank lines share (lines echoed from a Typed block's body carry its indent, which would turn deeper\n * nested lines into indented code).\n */\nexport function stripBlockLineEcho(markdown: string, known: (id: string) => boolean): string {\n let fence = 0\n const stripped = markdown.split('\\n').map((line) => {\n if (fence) {\n fence = fenceAfter(fence, line, false)\n return line\n }\n const bare = line.replace(/^\\[([^\\]\\s]+)\\] ?/, (prefix, id: string) => known(id) ? '' : prefix)\n fence = fenceAfter(0, bare, true)\n return bare\n })\n const indents = stripped.filter(line => line.trim()).map(line => /^[ \\t]*/.exec(line)![0].length)\n const common = indents.length ? Math.min(...indents) : 0\n return (common ? stripped.map(line => line.replace(new RegExp(`^[ \\\\t]{0,${common}}`), '')) : stripped).join('\\n')\n}\n\n/**\n * Removes the list and quote markers (`- `, `1. `, `> `) a model echoes from the lines of list items and quotes at the\n * start of each line of its Markdown.\n */\nexport function stripListMarkerEcho(markdown: string): string {\n return markdown.replace(/^(?:[ \\t]*(?:[-*+]|\\d+[.)])[ \\t]+|[ \\t]*>[ \\t]?)+/gm, '')\n}\n\n// ---------- Prompt -----------------------------------------------------------\n\n/** The block ID of the prompt's example line (also the target of its citation example). */\nexport const BLOCK_LINE_EXAMPLE_ID = '0f3c9a52-7d1e-4b8a-9c2f-5e6d7a8b9c0d'\n\n/** The text of the prompt's example line: a speaker line. */\nexport const BLOCK_LINE_EXAMPLE_TEXT = '**Anna:** Wir starten im Mai.'\n\n/** The example line of the prompt, written by `blockLine` like every line of the document. */\nexport const BLOCK_LINE_EXAMPLE = blockLine(BLOCK_LINE_EXAMPLE_ID, '', BLOCK_LINE_EXAMPLE_TEXT)\n\n/** The label of the document in the user message. */\nexport const BLOCK_LINES_LABEL = 'Dokument (aktueller Stand, eine Zeile pro Block, beginnend mit der Block-ID)'\n\n/** What the first lines of the system prompt say about the document's lines. */\nexport const BLOCK_LINE_INTRO = `Jede Zeile des Dokuments beginnt mit der ID ihres Blocks in eckigen Klammern, z. B. \\`${BLOCK_LINE_EXAMPLE}\\`. Redebeiträge beginnen nach der ID mit dem fett gesetzten Namen der Sprecherin bzw. des Sprechers und einem Doppelpunkt.`\n\n/** The list and quote blocks with the characters their lines carry. */\nexport const BLOCK_LINE_MARKERS = `Aufzählung („${listLinePrefix('', false, 1)}“), nummerierte Liste („${listLinePrefix('', true, 1)}“), Zitat („${quoteLinePrefix('')}“)`\n\n/** What the prompt says about lists and quotes in the document. */\nexport const BLOCK_LINE_LIST_TEXT = 'Listenpunkte und Zitate stehen nach der ID mit ihrem Zeichen; jeder Absatz darin hat eine eigene ID.'\n\n/** What the prompt says about the lines of a host block with block content (a callout). */\nexport const BLOCK_LINE_HOST_TEXT = `Im Dokument beginnt ein eigener Block mit Inhaltsblöcken mit der Zeile „${blockLine('ID', '', '<erste Zeile seiner Markdown-Form>')}“; seine Inhaltsblöcke folgen als eigene Zeilen mit IDs, um zwei Leerzeichen eingerückt.`\n\n/** What the prompt says about the lines of a Typed block. */\nexport const BLOCK_LINE_COMPOSITE_TEXT = `Im Dokument beginnt ein typisierter Block mit der Kopfzeile „${blockLine('ID', '', compositeLineHeader('Blocktyp', { feld: 'wert' }, ['Titel', 'Beschreibung', 'Tags: #a #b']))}“ (die Felder als JSON nur, wenn welche gesetzt sind; leere Teile fehlen samt ihrem „|“). Seine Inhaltsblöcke folgen als eigene Zeilen mit ihren IDs, um zwei Leerzeichen eingerückt; eine Zeile „${compositeLineClose('')}“ ohne ID schließt ihn. Das Feld „bib“ ist eine Literaturangabe als CSL-JSON, „derivation“ beschreibt, woraus der Block erzeugt wurde. Ein Verweis auf einen Block des Dokuments steht im Text als „[@<Block-ID>]“, mit Fundstelle als „[@<Block-ID>, S. 12]“.`\n\n/** What the prompt says about the Markdown of an operation: no echo of the line prefix (`stripBlockLineEcho` removes it when it comes anyway). */\nexport const BLOCK_LINE_ECHO_TEXT = '„markdown“ enthält nur den neuen Inhalt, ohne Block-ID und ohne das Listen- oder Zitatzeichen der Zeile.'\n\n/** What the retry message says about IDs. */\nexport const BLOCK_LINE_IDS_HINT = 'Verwende nur IDs, die im Dokument in eckigen Klammern stehen; erfinde keine IDs.'\n"],"mappings":";;;;;;;;;;;;;AAgBA,MAAM,SAAS;;AAGf,MAAa,iBAAiB;;AAG9B,SAAgB,UAAU,IAAmB,QAAgB,MAAsB;CACjF,OAAO,GAAG,KAAK,IAAI,GAAG,MAAM,KAAK,SAAS;AAC5C;;AAGA,SAAgB,gBAAgB,UAA0B;CACxD,OAAO,SAAS,QAAQ,aAAa,GAAG;AAC1C;;AAGA,SAAgB,iBAAiB,QAAwB;CACvD,OAAO,GAAG,SAAS;AACrB;;AAGA,SAAgB,gBAAgB,QAAwB;CACtD,OAAO,GAAG,OAAO;AACnB;;AAGA,SAAgB,eAAe,QAAgB,SAAkB,QAAwB;CACvF,OAAO,GAAG,SAAS,UAAU,GAAG,OAAO,MAAM;AAC/C;;AAGA,SAAgB,oBAAoB,QAAwB;CAC1D,OAAO,OAAO,QAAQ,mBAAkB,WAAU,IAAI,OAAO,OAAO,MAAM,CAAC;AAC7E;;AAGA,SAAgB,oBAAoB,UAA0B;CAC5D,OAAO,gBAAgB,SAAS,QAAQ,eAAe,EAAE,CAAC;AAC5D;;;;;AAMA,SAAgB,oBAAoB,MAAc,MAAe,QAAmC;CAElG,OAAO,CAAC,OAAO,OADA,QAAQ,OAAO,SAAS,YAAY,OAAO,KAAK,IAAI,CAAC,CAAC,SAAS,IAAI,KAAK,UAAU,IAAI,MAAM,MAC3E,GAAG,OAAO,OAAO,OAAO,CAAC,CAAC,CAAC,KAAK,KAAK;AACvE;;AAGA,SAAgB,mBAAmB,QAAwB;CACzD,OAAO,GAAG,iBAAiB,MAAM,EAAE;AACrC;AAYA,MAAM,YAAY;;AAElB,MAAM,aAAa;AACnB,MAAM,cAAc;;AAEpB,MAAM,cAAc;;;;;AAMpB,SAAS,WAAW,OAAe,MAAc,OAAwB;CACvE,IAAI,OAAO;EACT,MAAM,UAAU,YAAY,KAAK,IAAI;EACrC,OAAO,WAAW,QAAQ,EAAE,CAAE,UAAU,QAAQ,IAAI;CACtD;CACA,MAAM,UAAU,QAAQ,WAAW,KAAK,IAAI,IAAI;CAChD,OAAO,UAAU,QAAQ,EAAE,CAAE,SAAS;AACxC;AAEA,MAAM,0BAA+B,IAAI,IAAI;;;;;;;;;;;AAY7C,SAAgB,eAAe,MAA0B;CACvD,MAAM,sBAAM,IAAI,IAAY;CAC5B,MAAM,yBAAS,IAAI,IAAyB;CAE5C,MAAM,OAAwD,CAAC;CAC/D,IAAI,QAAQ;CAEZ,KAAK,MAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;EACnC,MAAM,KAAK,UAAU,KAAK,IAAI,CAAC,GAAG;EAClC,IAAI,OAAO;GACT,QAAQ,WAAW,OAAO,MAAM,KAAK;GACrC;EACF;EAEA,IAAI,CAAC,MAAM,SAAA,oCAAyB;EACpC,MAAM,UAAU,KAAK,MAAM,GAAG,SAAS,CAAC;EACxC,QAAQ,WAAW,GAAG,SAAS,IAAI;EACnC,IAAI,IAAI,EAAE;EAEV,MAAM,SAAS,UAAU,KAAK,OAAO,CAAC,CAAE,EAAE,CAAC;EAC3C,MAAM,WAAW,UAAU,KAAK,YAAY,KAAK,OAAO,CAAC,CAAE,EAAE;EAC7D,OAAO,KAAK,UAAU,KAAK,GAAG,EAAE,CAAC,CAAE,UAAU,QAAQ,KAAK,IAAI;EAC9D,KAAK,MAAM,SAAS,MAAM;GACxB,IAAI,CAAC,MAAM,QAAQ,MAAM,OAAO,IAAI;GACpC,MAAM,SAAS,OAAO,IAAI,MAAM,EAAE;GAClC,IAAI,QAAQ,OAAO,IAAI,EAAE;QACpB,OAAO,IAAI,MAAM,oBAAI,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC;EACzC;EACA,KAAK,KAAK;GAAE;GAAI;GAAQ,MAAM,CAAC,aAAa,KAAK,GAAG,EAAE,CAAC,EAAE,QAAQ;EAAM,CAAC;CAC1E;CACA,OAAO;EAAE;EAAK,QAAO,OAAM,OAAO,IAAI,EAAE,KAAK;CAAQ;AACvD;;;;;;;AAQA,SAAgB,mBAAmB,UAAkB,OAAwC;CAC3F,IAAI,QAAQ;CACZ,MAAM,WAAW,SAAS,MAAM,IAAI,CAAC,CAAC,KAAK,SAAS;EAClD,IAAI,OAAO;GACT,QAAQ,WAAW,OAAO,MAAM,KAAK;GACrC,OAAO;EACT;EACA,MAAM,OAAO,KAAK,QAAQ,sBAAsB,QAAQ,OAAe,MAAM,EAAE,IAAI,KAAK,MAAM;EAC9F,QAAQ,WAAW,GAAG,MAAM,IAAI;EAChC,OAAO;CACT,CAAC;CACD,MAAM,UAAU,SAAS,QAAO,SAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,KAAI,SAAQ,UAAU,KAAK,IAAI,CAAC,CAAE,EAAE,CAAC,MAAM;CAChG,MAAM,SAAS,QAAQ,SAAS,KAAK,IAAI,GAAG,OAAO,IAAI;CACvD,QAAQ,SAAS,SAAS,KAAI,SAAQ,KAAK,QAAQ,IAAI,OAAO,aAAa,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,SAAA,CAAU,KAAK,IAAI;AACnH;;;;;AAMA,SAAgB,oBAAoB,UAA0B;CAC5D,OAAO,SAAS,QAAQ,uDAAuD,EAAE;AACnF;;AAKA,MAAa,wBAAwB;;AAGrC,MAAa,0BAA0B;;AAGvC,MAAa,qBAAqB,UAAU,uBAAuB,IAAI,uBAAuB;;AAG9F,MAAa,oBAAoB;;AAGjC,MAAa,mBAAmB,yFAAyF,mBAAmB;;AAG5I,MAAa,qBAAqB,gBAAgB,eAAe,IAAI,OAAO,CAAC,EAAE,0BAA0B,eAAe,IAAI,MAAM,CAAC,EAAE,cAAc,gBAAgB,EAAE,EAAE;;AAGvK,MAAa,uBAAuB;;AAGpC,MAAa,uBAAuB,2EAA2E,UAAU,MAAM,IAAI,oCAAoC,EAAE;;AAGzK,MAAa,4BAA4B,gEAAgE,UAAU,MAAM,IAAI,oBAAoB,YAAY,EAAE,MAAM,OAAO,GAAG;CAAC;CAAS;CAAgB;AAAa,CAAC,CAAC,EAAE,oMAAoM,mBAAmB,EAAE,EAAE;;AAGrb,MAAa,uBAAuB;;AAGpC,MAAa,sBAAsB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StructureMode } from "../../../settings/values.js";
|
|
2
2
|
import "../../../settings/index.js";
|
|
3
|
-
import { AiBlock,
|
|
3
|
+
import { AiBlock, AiContextBlockType } from "../../../core/feature.js";
|
|
4
4
|
import { AgentOp, AgentOpFeedback } from "./agent-ops.js";
|
|
5
5
|
import { ModelMessage } from "ai";
|
|
6
6
|
//#region src/features/ai/protocol/chat.d.ts
|
|
@@ -32,16 +32,16 @@ export declare const CITATION_HREF_PREFIX = "#block-";
|
|
|
32
32
|
* write now and then despite the instructions; whether the ID exists is up to the caller.
|
|
33
33
|
*/
|
|
34
34
|
export declare function citationBlockId(href: unknown): string | null;
|
|
35
|
-
/** A
|
|
36
|
-
export type
|
|
35
|
+
/** A Block type as the chat model learns it: the client sends the Block types of the editor's `aiContext` with every message. */
|
|
36
|
+
export type ChatBlockType = Pick<AiContextBlockType, 'id' | 'label' | 'fields' | 'purpose'>;
|
|
37
37
|
/** A host-defined block as the chat model learns it: the editor's `aiContext.blocks`, sent with every message. */
|
|
38
38
|
export type ChatBlock = AiBlock;
|
|
39
39
|
/**
|
|
40
|
-
* What the model may build and convert into: the editor's
|
|
40
|
+
* What the model may build and convert into: the editor's Block types and host blocks, the `convert` targets it
|
|
41
41
|
* offers, and the user's preferred structure of new content (settings `blocks.structure`).
|
|
42
42
|
*/
|
|
43
43
|
export interface ChatBlockModel {
|
|
44
|
-
|
|
44
|
+
blockTypes: readonly ChatBlockType[];
|
|
45
45
|
blocks: readonly ChatBlock[];
|
|
46
46
|
targets: readonly string[];
|
|
47
47
|
structure: StructureMode;
|
|
@@ -24,7 +24,7 @@ const FIELD_TYPES = {
|
|
|
24
24
|
number: "Zahl",
|
|
25
25
|
select: "Auswahl",
|
|
26
26
|
multiselect: "Mehrfachauswahl",
|
|
27
|
-
reference: "Block-ID eines
|
|
27
|
+
reference: "Block-ID eines typisierten Blocks",
|
|
28
28
|
bibliography: "Literaturangabe als CSL-JSON-Objekt",
|
|
29
29
|
derivation: "Herkunft, nur lesen"
|
|
30
30
|
};
|
|
@@ -34,23 +34,23 @@ function fieldText(field) {
|
|
|
34
34
|
return `${field.key} (${field.label}${values})`;
|
|
35
35
|
}
|
|
36
36
|
/** „Blockmodell“: the document's line format for composites and host blocks holding blocks, the fence the model writes composites in, and `convert`. */
|
|
37
|
-
function blockModelText({
|
|
38
|
-
const composites = structure === "
|
|
39
|
-
const example =
|
|
37
|
+
function blockModelText({ blockTypes, blocks, targets, structure }) {
|
|
38
|
+
const composites = structure === "structured" && blockTypes.length > 0;
|
|
39
|
+
const example = blockTypes.find((blockType) => blockType.fields.some((field) => field.options?.length)) ?? blockTypes[0];
|
|
40
40
|
const exampleField = example?.fields.find((field) => field.options?.length);
|
|
41
41
|
const exampleMeta = exampleField ? ` {"${exampleField.key}":"${exampleField.options.at(-1).value}"}` : "";
|
|
42
42
|
return [
|
|
43
43
|
"Blockmodell:",
|
|
44
|
-
`Blocktypen: Absatz, Überschrift (#, ##, ###), ${BLOCK_LINE_MARKERS}, Codeblock, Redebeitrag („**Name:** Text“) und
|
|
44
|
+
`Blocktypen: Absatz, Überschrift (#, ##, ###), ${BLOCK_LINE_MARKERS}, Codeblock, Redebeitrag („**Name:** Text“) und typisierte Blöcke. ${BLOCK_LINE_LIST_TEXT}`,
|
|
45
45
|
...blocks.length ? [`Eigene Blöcke: ${blocks.map((block) => `${block.id} (${block.label}): ${block.description} Markdown-Form: „${block.syntax.replace(/\n/g, "\\n")}“. Beispiel: „${block.example.replace(/\n/g, "\\n")}“`).join(" ")}`, `${BLOCK_LINE_HOST_TEXT} „update“ auf seine ID mit vollständigem Markdown ersetzt den ganzen Block; „add“ nach einem seiner Inhaltsblöcke fügt innerhalb des Blocks ein, ein Block derselben Art danach.`] : [],
|
|
46
|
-
composites ? "Bevorzugte Gliederung:
|
|
47
|
-
...
|
|
48
|
-
`
|
|
49
|
-
`
|
|
50
|
-
`In „markdown“ schreibst du einen
|
|
51
|
-
"„update“ auf einen
|
|
46
|
+
composites ? "Bevorzugte Gliederung: typisierte Blöcke. Neue Inhalte gliederst du mit typisierten Blöcken statt mit Überschriften; Unterabschnitte sind verschachtelte typisierte Blöcke (Zaun im Zaun, jeder Zaun endet mit einer eigenen Zeile „:::“). Markdown-Überschriften schreibst du nur als Titelzeile eines typisierten Blocks." : "Bevorzugte Gliederung: Überschriften. Neue Inhalte gliederst du mit Überschriften (##, ###) statt mit typisierten Blöcken; einen typisierten Block schreibst du nur, wenn ausdrücklich ein Block (Abschnitt, Aufgabe, Notiz …) verlangt wird oder du einen bestehenden typisierten Block änderst.",
|
|
47
|
+
...blockTypes.length ? [
|
|
48
|
+
`Typisierte Blöcke sind Blöcke mit Titel, Beschreibung, Tags, Feldern und eigenen Inhaltsblöcken. ${BLOCK_LINE_COMPOSITE_TEXT}`,
|
|
49
|
+
`Blocktypen der typisierten Blöcke: ${blockTypes.map((blockType) => `${blockType.id} (${blockType.label}${blockType.purpose ? `: ${blockType.purpose}` : ""}; ${blockType.fields.length ? `Felder: ${blockType.fields.map(fieldText).join(", ")}` : "keine Felder"})`).join("; ")}.`,
|
|
50
|
+
`In „markdown“ schreibst du einen typisierten Block ohne IDs und ohne Einrückung als Zaun: die Zeile „::: Blocktyp {"feld":"wert"}“ (Felder als JSON, nur gesetzte), dann „## Titel“, „> Beschreibung“ und „Tags: #a #b“ (jeweils nur, wenn vorhanden), dann die Inhaltsblöcke als Markdown, zuletzt die Zeile „:::“. Beispiel: „::: ${example?.id ?? "note"}${exampleMeta}\\n## Angebot prüfen\\n- Preise vergleichen\\n- Rückmeldung an Anna\\n:::“.`,
|
|
51
|
+
"„update“ auf einen typisierten Block mit Markdown ohne :::-Zaun ersetzt nur seinen Inhalt (Kinder); mit Zaun den ganzen Block (Blocktyp, Felder, Titel, Beschreibung, Tags und Inhalt)."
|
|
52
52
|
] : [],
|
|
53
|
-
`„convert“ wandelt den Block „id“ in den Blocktyp „to“ um und behält seinen Inhalt. Erlaubte Werte für „to“: ${targets.join(", ")}. Eine Überschrift, die zum
|
|
53
|
+
`„convert“ wandelt den Block „id“ in den Blocktyp „to“ um und behält seinen Inhalt. Erlaubte Werte für „to“: ${targets.join(", ")}. Eine Überschrift, die zum typisierten Block wird, nimmt die folgenden Blöcke bis zur nächsten Überschrift gleicher oder höherer Ebene als Inhalt mit; ein typisierter Block, der zu einem anderen Blocktyp wird, behält Beschreibung, Tags und Felder als Textzeilen; wird er zur Überschrift, werden seine inneren typisierten Blöcke zu Unterüberschriften.`,
|
|
54
54
|
"Sollen sich Blocktyp und Inhalt oder Felder zugleich ändern (z. B. ein Absatz wird zu einer Aufgabe mit Status), nimm statt „convert“ ein „update“ mit dem vollständigen neuen Markdown samt :::-Zaun; jeder Block bekommt höchstens eine Operation."
|
|
55
55
|
];
|
|
56
56
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.js","names":[],"sources":["../../../../src/features/ai/protocol/chat.ts"],"sourcesContent":["// i18n-ignore-file: model-facing chat system prompt and messages (German prompts stay German whatever the editor's language)\nimport type { ModelMessage } from 'ai'\nimport type { AiBlock, AiContextKind } from '../../../core/feature'\nimport type { StructureMode } from '../../../settings'\nimport { AGENT_TOOL, type AgentOp, type AgentOpFeedback, agentFeedbackText, agentShownMessage } from './agent-ops'\nimport { BLOCK_LINE_COMPOSITE_TEXT, BLOCK_LINE_ECHO_TEXT, BLOCK_LINE_EXAMPLE_ID, BLOCK_LINE_HOST_TEXT, BLOCK_LINE_INTRO, BLOCK_LINE_LIST_TEXT, BLOCK_LINE_MARKERS, BLOCK_LINES_LABEL } from './block-lines'\n\n/**\n * One turn of the document chat; the conversation lives on the client and is sent in full with every message.\n * A user turn carries the decisions on earlier proposals made since the previous turn (`feedback`); an assistant turn\n * the edit operations it proposed (`ops`, possibly without any text) and how many invalid ones were dropped.\n */\nexport type DocumentChatMessage =\n | { role: 'user', content: string, feedback?: AgentOpFeedback[] }\n | { role: 'assistant', content: string, ops?: AgentOp[], dropped?: number }\n\n/** Input limits (characters / messages) of `POST /api/ai/chat`; the client trims to fit before sending. */\nexport const CHAT_LIMITS = { document: 120000, message: 8000, messages: 40 } as const\n\n/** Link target prefix of a quote citation: `[„Zitat“](#block-<id>)`. */\nexport const CITATION_HREF_PREFIX = '#block-'\n\n/**\n * The block ID a citation link points to, or `null` for any other href. Also accepts a bare `#<id>`, which models\n * write now and then despite the instructions; whether the ID exists is up to the caller.\n */\nexport function citationBlockId(href: unknown): string | null {\n if (typeof href !== 'string' || !href.startsWith('#')) return null\n return (href.startsWith(CITATION_HREF_PREFIX) ? href.slice(CITATION_HREF_PREFIX.length) : href.slice(1)) || null\n}\n\n/** A composite kind as the chat model learns it: the client sends the kinds of the editor's `aiContext` with every message. */\nexport type ChatCompositeKind = Pick<AiContextKind, 'id' | 'label' | 'fields' | 'purpose'>\ntype ChatField = ChatCompositeKind['fields'][number]\n\n/** A host-defined block as the chat model learns it: the editor's `aiContext.blocks`, sent with every message. */\nexport type ChatBlock = AiBlock\n\n/**\n * What the model may build and convert into: the editor's composite kinds and host blocks, the `convert` targets it\n * offers, and the user's preferred structure of new content (settings `blocks.structure`).\n */\nexport interface ChatBlockModel { kinds: readonly ChatCompositeKind[], blocks: readonly ChatBlock[], targets: readonly string[], structure: StructureMode }\n\nconst FIELD_TYPES: Record<NonNullable<ChatField['type']>, string> = { text: 'Text', textarea: 'Langtext', date: 'Datum JJJJ-MM-TT', number: 'Zahl', select: 'Auswahl', multiselect: 'Mehrfachauswahl', reference: 'Block-ID eines Bausteins', bibliography: 'Literaturangabe als CSL-JSON-Objekt', derivation: 'Herkunft, nur lesen' }\n\n/** `status (Status: open = Offen, doing = In Arbeit, done = Erledigt)`, `due (Fällig, Datum JJJJ-MM-TT)`. */\nfunction fieldText(field: ChatField): string {\n const values = field.options?.length ? `: ${field.options.map(option => `${option.value} = ${option.label}`).join(', ')}${field.type === 'multiselect' ? `; ${FIELD_TYPES.multiselect}, mehrere Werte als JSON-Liste` : ''}` : `, ${FIELD_TYPES[field.type ?? 'text']}`\n return `${field.key} (${field.label}${values})`\n}\n\n/** „Blockmodell“: the document's line format for composites and host blocks holding blocks, the fence the model writes composites in, and `convert`. */\nfunction blockModelText({ kinds, blocks, targets, structure }: ChatBlockModel): string[] {\n const composites = structure === 'composite' && kinds.length > 0\n const example = kinds.find(kind => kind.fields.some(field => field.options?.length)) ?? kinds[0]\n const exampleField = example?.fields.find(field => field.options?.length)\n const exampleMeta = exampleField ? ` {\"${exampleField.key}\":\"${exampleField.options!.at(-1)!.value}\"}` : ''\n return [\n 'Blockmodell:',\n `Blocktypen: Absatz, Überschrift (#, ##, ###), ${BLOCK_LINE_MARKERS}, Codeblock, Redebeitrag („**Name:** Text“) und Bausteine. ${BLOCK_LINE_LIST_TEXT}`,\n ...(blocks.length\n ? [\n `Eigene Blöcke: ${blocks.map(block => `${block.id} (${block.label}): ${block.description} Markdown-Form: „${block.syntax.replace(/\\n/g, '\\\\n')}“. Beispiel: „${block.example.replace(/\\n/g, '\\\\n')}“`).join(' ')}`,\n `${BLOCK_LINE_HOST_TEXT} „update“ auf seine ID mit vollständigem Markdown ersetzt den ganzen Block; „add“ nach einem seiner Inhaltsblöcke fügt innerhalb des Blocks ein, ein Block derselben Art danach.`,\n ]\n : []),\n composites\n ? 'Bevorzugte Gliederung: Bausteine. Neue Inhalte gliederst du mit Bausteinen statt mit Überschriften; Unterabschnitte sind verschachtelte Bausteine (Zaun im Zaun, jeder Zaun endet mit einer eigenen Zeile „:::“). Markdown-Überschriften schreibst du nur als Titelzeile eines Bausteins.'\n : 'Bevorzugte Gliederung: Überschriften. Neue Inhalte gliederst du mit Überschriften (##, ###) statt mit Bausteinen; einen Baustein schreibst du nur, wenn ausdrücklich ein Baustein (Abschnitt, Aufgabe, Notiz …) verlangt wird oder du einen bestehenden Baustein änderst.',\n ...(kinds.length\n ? [\n `Bausteine sind Blöcke mit Titel, Beschreibung, Tags, Feldern und eigenen Inhaltsblöcken. ${BLOCK_LINE_COMPOSITE_TEXT}`,\n `Arten von Bausteinen: ${kinds.map(kind => `${kind.id} (${kind.label}${kind.purpose ? `: ${kind.purpose}` : ''}; ${kind.fields.length ? `Felder: ${kind.fields.map(fieldText).join(', ')}` : 'keine Felder'})`).join('; ')}.`,\n `In „markdown“ schreibst du einen Baustein ohne IDs und ohne Einrückung als Zaun: die Zeile „::: Art {\"feld\":\"wert\"}“ (Felder als JSON, nur gesetzte), dann „## Titel“, „> Beschreibung“ und „Tags: #a #b“ (jeweils nur, wenn vorhanden), dann die Inhaltsblöcke als Markdown, zuletzt die Zeile „:::“. Beispiel: „::: ${example?.id ?? 'note'}${exampleMeta}\\\\n## Angebot prüfen\\\\n- Preise vergleichen\\\\n- Rückmeldung an Anna\\\\n:::“.`,\n '„update“ auf einen Baustein mit Markdown ohne :::-Zaun ersetzt nur seinen Inhalt (Kinder); mit Zaun den ganzen Baustein (Art, Felder, Titel, Beschreibung, Tags und Inhalt).',\n ]\n : []),\n `„convert“ wandelt den Block „id“ in den Blocktyp „to“ um und behält seinen Inhalt. Erlaubte Werte für „to“: ${targets.join(', ')}. Eine Überschrift, die zum Baustein wird, nimmt die folgenden Blöcke bis zur nächsten Überschrift gleicher oder höherer Ebene als Inhalt mit; ein Baustein, der zu einem anderen Blocktyp wird, behält Beschreibung, Tags und Felder als Textzeilen; wird er zur Überschrift, werden seine inneren Bausteine zu Unterüberschriften.`,\n 'Sollen sich Blocktyp und Inhalt oder Felder zugleich ändern (z. B. ein Absatz wird zu einer Aufgabe mit Status), nimm statt „convert“ ein „update“ mit dem vollständigen neuen Markdown samt :::-Zaun; jeder Block bekommt höchstens eine Operation.',\n ]\n}\n\n/** The system prompt: answering with citations, editing through `edit_document`, and the editor's block model. */\nfunction chatSystem(blockModel: ChatBlockModel): string {\n return [\n 'Du beantwortest Fragen zu einem Dokument, meist dem Transkript eines Gesprächs, und bearbeitest es auf Wunsch. Das Dokument steht in der letzten Nachricht der Nutzerin bzw. des Nutzers und ist der aktuelle Stand; frühere Nachrichten bezogen sich womöglich auf einen älteren Stand.',\n BLOCK_LINE_INTRO,\n '',\n 'Fragen:',\n `Belege deine Antworten mit wörtlichen Zitaten: ein zusammenhängender, unveränderter Ausschnitt aus einem einzigen Block. Jedes Zitat ist ein Markdown-Link, dessen Ziel „${CITATION_HREF_PREFIX}“ gefolgt von der vollständigen ID dieses Blocks ist: [„Zitat“](${CITATION_HREF_PREFIX}ID).`,\n `Beispiel zur Zeile oben: Anna kündigt den Start an: [„Wir starten im Mai.“](${CITATION_HREF_PREFIX}${BLOCK_LINE_EXAMPLE_ID})`,\n 'Verwende nur IDs, die im Dokument vorkommen, und nenne IDs nie außerhalb solcher Links.',\n 'Steht die Antwort nicht im Dokument, sag das ehrlich, statt etwas zu erfinden.',\n 'Antworte knapp in Markdown (Absätze, Aufzählungen, **fett**) und in der Sprache der Frage.',\n '',\n 'Änderungen:',\n `Bittet die Nutzerin bzw. der Nutzer darum, das Dokument zu ändern (kürzen, umformulieren, ergänzen, löschen, umwandeln …), rufe das Werkzeug ${AGENT_TOOL} auf, statt den neuen Text im Chat zu schreiben. Schreib davor höchstens ein bis zwei Sätze dazu, was du änderst. Bei Fragen rufst du das Werkzeug nicht auf.`,\n 'Operationen: „update“ ersetzt den Inhalt des Blocks „id“ durch „markdown“; „delete“ löscht den Block „id“; „add“ fügt „markdown“ (ein oder mehrere Blöcke, durch Leerzeilen getrennt) nach dem Block „afterId“ ein („afterId“ gehört bei „add“ immer dazu, für den Dokumentanfang schreibst du ausdrücklich null; mehrere „add“ nach demselben Block werden in der Reihenfolge eingefügt, in der du sie schreibst); „convert“ wandelt den Block „id“ in den Blocktyp „to“ um.',\n `${BLOCK_LINE_ECHO_TEXT} Redebeiträge behalten den fett gesetzten Namen mit Doppelpunkt am Anfang; ein anderer Name wechselt die Sprecherin bzw. den Sprecher. Neue Redebeiträge schreibst du ebenso als „**Name:** Text“.`,\n 'Ändere nur die Blöcke, die die Bitte betrifft; lass unveränderte Blöcke weg. Jeder Block höchstens einmal; eine Operation auf einen Block innerhalb eines Blocks, den eine andere Operation ersetzt oder löscht, ist ungültig (schreibe die Änderung dann in das Markdown der äußeren Operation). Verwende nur IDs aus dem Dokument. Nennt die Nachricht einen Bearbeitungsbereich, beziehen sich alle IDs und afterIds ausschließlich auf Blöcke daraus.',\n 'Jede Änderung wird der Nutzerin bzw. dem Nutzer im Dokument zur Prüfung angezeigt und einzeln übernommen oder abgelehnt. Die Entscheidungen erhältst du mit einer späteren Nachricht („Entscheidungen zu deinen letzten Vorschlägen: …“). Geh auf abgelehnte Vorschläge ein und wiederhole sie nicht unverändert.',\n '',\n ...blockModelText(blockModel),\n ].join('\\n')\n}\n\n/** A user turn as the model reads it: decisions on earlier proposals first, then the message. */\nfunction userText(content: string, feedback: readonly AgentOpFeedback[] | undefined): string {\n const decisions = agentFeedbackText(feedback ?? [])\n return decisions ? `${decisions}\\n\\nNachricht: ${content}` : content\n}\n\n/**\n * Model messages for a chat turn: the history as sent (proposed operations as `edit_document` tool calls), with the\n * current document placed in the last (user) message next to the scope, the latest decisions and the message —\n * document content never goes into the system prompt (the editor's block model does). `scope`: IDs the edits are\n * limited to (null: whole document).\n */\nexport function documentChatMessages(messages: readonly DocumentChatMessage[], document: string, scope: readonly string[] | null, blockModel: ChatBlockModel): ModelMessage[] {\n const history = messages.slice(0, -1).flatMap((message, index): ModelMessage[] => {\n if (message.role === 'user') return [{ role: 'user', content: userText(message.content, message.feedback) }]\n if (!message.ops?.length && !message.dropped) return [{ role: 'assistant', content: message.content }]\n const ops = message.ops ?? []\n const toolCallId = `edit_${index}`\n return [\n {\n role: 'assistant',\n content: [\n ...(message.content ? [{ type: 'text' as const, text: message.content }] : []),\n { type: 'tool-call', toolCallId, toolName: AGENT_TOOL, input: { ops: ops.map(({ op: _op, ...rest }) => rest) } },\n ],\n },\n {\n role: 'tool',\n content: [{ type: 'tool-result', toolCallId, toolName: AGENT_TOOL, output: { type: 'text', value: agentShownMessage(ops, message.dropped ?? 0) } }],\n },\n ]\n })\n const last = messages.at(-1)! as Extract<DocumentChatMessage, { role: 'user' }>\n const range = scope\n ? `Bearbeitungsbereich: die Auswahl der Nutzerin bzw. des Nutzers. Änderungen (id und afterId) nur an diesen Blöcken: ${scope.join(', ')}`\n : 'Bearbeitungsbereich: das ganze Dokument.'\n const decisions = agentFeedbackText(last.feedback ?? [])\n return [\n { role: 'system', content: chatSystem(blockModel) },\n ...history,\n {\n role: 'user',\n content: [\n `${BLOCK_LINES_LABEL}:\\n\"\"\"\\n${document}\\n\"\"\"`,\n range,\n ...(decisions ? [decisions] : []),\n `Nachricht: ${last.content}`,\n ].join('\\n\\n'),\n },\n ]\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chat.js","names":[],"sources":["../../../../src/features/ai/protocol/chat.ts"],"sourcesContent":["// i18n-ignore-file: model-facing chat system prompt and messages (German prompts stay German whatever the editor's language)\nimport type { ModelMessage } from 'ai'\nimport type { AiBlock, AiContextBlockType } from '../../../core/feature'\nimport type { StructureMode } from '../../../settings'\nimport { AGENT_TOOL, type AgentOp, type AgentOpFeedback, agentFeedbackText, agentShownMessage } from './agent-ops'\nimport { BLOCK_LINE_COMPOSITE_TEXT, BLOCK_LINE_ECHO_TEXT, BLOCK_LINE_EXAMPLE_ID, BLOCK_LINE_HOST_TEXT, BLOCK_LINE_INTRO, BLOCK_LINE_LIST_TEXT, BLOCK_LINE_MARKERS, BLOCK_LINES_LABEL } from './block-lines'\n\n/**\n * One turn of the document chat; the conversation lives on the client and is sent in full with every message.\n * A user turn carries the decisions on earlier proposals made since the previous turn (`feedback`); an assistant turn\n * the edit operations it proposed (`ops`, possibly without any text) and how many invalid ones were dropped.\n */\nexport type DocumentChatMessage =\n | { role: 'user', content: string, feedback?: AgentOpFeedback[] }\n | { role: 'assistant', content: string, ops?: AgentOp[], dropped?: number }\n\n/** Input limits (characters / messages) of `POST /api/ai/chat`; the client trims to fit before sending. */\nexport const CHAT_LIMITS = { document: 120000, message: 8000, messages: 40 } as const\n\n/** Link target prefix of a quote citation: `[„Zitat“](#block-<id>)`. */\nexport const CITATION_HREF_PREFIX = '#block-'\n\n/**\n * The block ID a citation link points to, or `null` for any other href. Also accepts a bare `#<id>`, which models\n * write now and then despite the instructions; whether the ID exists is up to the caller.\n */\nexport function citationBlockId(href: unknown): string | null {\n if (typeof href !== 'string' || !href.startsWith('#')) return null\n return (href.startsWith(CITATION_HREF_PREFIX) ? href.slice(CITATION_HREF_PREFIX.length) : href.slice(1)) || null\n}\n\n/** A Block type as the chat model learns it: the client sends the Block types of the editor's `aiContext` with every message. */\nexport type ChatBlockType = Pick<AiContextBlockType, 'id' | 'label' | 'fields' | 'purpose'>\ntype ChatField = ChatBlockType['fields'][number]\n\n/** A host-defined block as the chat model learns it: the editor's `aiContext.blocks`, sent with every message. */\nexport type ChatBlock = AiBlock\n\n/**\n * What the model may build and convert into: the editor's Block types and host blocks, the `convert` targets it\n * offers, and the user's preferred structure of new content (settings `blocks.structure`).\n */\nexport interface ChatBlockModel { blockTypes: readonly ChatBlockType[], blocks: readonly ChatBlock[], targets: readonly string[], structure: StructureMode }\n\nconst FIELD_TYPES: Record<NonNullable<ChatField['type']>, string> = { text: 'Text', textarea: 'Langtext', date: 'Datum JJJJ-MM-TT', number: 'Zahl', select: 'Auswahl', multiselect: 'Mehrfachauswahl', reference: 'Block-ID eines typisierten Blocks', bibliography: 'Literaturangabe als CSL-JSON-Objekt', derivation: 'Herkunft, nur lesen' }\n\n/** `status (Status: open = Offen, doing = In Arbeit, done = Erledigt)`, `due (Fällig, Datum JJJJ-MM-TT)`. */\nfunction fieldText(field: ChatField): string {\n const values = field.options?.length ? `: ${field.options.map(option => `${option.value} = ${option.label}`).join(', ')}${field.type === 'multiselect' ? `; ${FIELD_TYPES.multiselect}, mehrere Werte als JSON-Liste` : ''}` : `, ${FIELD_TYPES[field.type ?? 'text']}`\n return `${field.key} (${field.label}${values})`\n}\n\n/** „Blockmodell“: the document's line format for composites and host blocks holding blocks, the fence the model writes composites in, and `convert`. */\nfunction blockModelText({ blockTypes, blocks, targets, structure }: ChatBlockModel): string[] {\n const composites = structure === 'structured' && blockTypes.length > 0\n const example = blockTypes.find(blockType => blockType.fields.some(field => field.options?.length)) ?? blockTypes[0]\n const exampleField = example?.fields.find(field => field.options?.length)\n const exampleMeta = exampleField ? ` {\"${exampleField.key}\":\"${exampleField.options!.at(-1)!.value}\"}` : ''\n return [\n 'Blockmodell:',\n `Blocktypen: Absatz, Überschrift (#, ##, ###), ${BLOCK_LINE_MARKERS}, Codeblock, Redebeitrag („**Name:** Text“) und typisierte Blöcke. ${BLOCK_LINE_LIST_TEXT}`,\n ...(blocks.length\n ? [\n `Eigene Blöcke: ${blocks.map(block => `${block.id} (${block.label}): ${block.description} Markdown-Form: „${block.syntax.replace(/\\n/g, '\\\\n')}“. Beispiel: „${block.example.replace(/\\n/g, '\\\\n')}“`).join(' ')}`,\n `${BLOCK_LINE_HOST_TEXT} „update“ auf seine ID mit vollständigem Markdown ersetzt den ganzen Block; „add“ nach einem seiner Inhaltsblöcke fügt innerhalb des Blocks ein, ein Block derselben Art danach.`,\n ]\n : []),\n composites\n ? 'Bevorzugte Gliederung: typisierte Blöcke. Neue Inhalte gliederst du mit typisierten Blöcken statt mit Überschriften; Unterabschnitte sind verschachtelte typisierte Blöcke (Zaun im Zaun, jeder Zaun endet mit einer eigenen Zeile „:::“). Markdown-Überschriften schreibst du nur als Titelzeile eines typisierten Blocks.'\n : 'Bevorzugte Gliederung: Überschriften. Neue Inhalte gliederst du mit Überschriften (##, ###) statt mit typisierten Blöcken; einen typisierten Block schreibst du nur, wenn ausdrücklich ein Block (Abschnitt, Aufgabe, Notiz …) verlangt wird oder du einen bestehenden typisierten Block änderst.',\n ...(blockTypes.length\n ? [\n `Typisierte Blöcke sind Blöcke mit Titel, Beschreibung, Tags, Feldern und eigenen Inhaltsblöcken. ${BLOCK_LINE_COMPOSITE_TEXT}`,\n `Blocktypen der typisierten Blöcke: ${blockTypes.map(blockType => `${blockType.id} (${blockType.label}${blockType.purpose ? `: ${blockType.purpose}` : ''}; ${blockType.fields.length ? `Felder: ${blockType.fields.map(fieldText).join(', ')}` : 'keine Felder'})`).join('; ')}.`,\n `In „markdown“ schreibst du einen typisierten Block ohne IDs und ohne Einrückung als Zaun: die Zeile „::: Blocktyp {\"feld\":\"wert\"}“ (Felder als JSON, nur gesetzte), dann „## Titel“, „> Beschreibung“ und „Tags: #a #b“ (jeweils nur, wenn vorhanden), dann die Inhaltsblöcke als Markdown, zuletzt die Zeile „:::“. Beispiel: „::: ${example?.id ?? 'note'}${exampleMeta}\\\\n## Angebot prüfen\\\\n- Preise vergleichen\\\\n- Rückmeldung an Anna\\\\n:::“.`,\n '„update“ auf einen typisierten Block mit Markdown ohne :::-Zaun ersetzt nur seinen Inhalt (Kinder); mit Zaun den ganzen Block (Blocktyp, Felder, Titel, Beschreibung, Tags und Inhalt).',\n ]\n : []),\n `„convert“ wandelt den Block „id“ in den Blocktyp „to“ um und behält seinen Inhalt. Erlaubte Werte für „to“: ${targets.join(', ')}. Eine Überschrift, die zum typisierten Block wird, nimmt die folgenden Blöcke bis zur nächsten Überschrift gleicher oder höherer Ebene als Inhalt mit; ein typisierter Block, der zu einem anderen Blocktyp wird, behält Beschreibung, Tags und Felder als Textzeilen; wird er zur Überschrift, werden seine inneren typisierten Blöcke zu Unterüberschriften.`,\n 'Sollen sich Blocktyp und Inhalt oder Felder zugleich ändern (z. B. ein Absatz wird zu einer Aufgabe mit Status), nimm statt „convert“ ein „update“ mit dem vollständigen neuen Markdown samt :::-Zaun; jeder Block bekommt höchstens eine Operation.',\n ]\n}\n\n/** The system prompt: answering with citations, editing through `edit_document`, and the editor's block model. */\nfunction chatSystem(blockModel: ChatBlockModel): string {\n return [\n 'Du beantwortest Fragen zu einem Dokument, meist dem Transkript eines Gesprächs, und bearbeitest es auf Wunsch. Das Dokument steht in der letzten Nachricht der Nutzerin bzw. des Nutzers und ist der aktuelle Stand; frühere Nachrichten bezogen sich womöglich auf einen älteren Stand.',\n BLOCK_LINE_INTRO,\n '',\n 'Fragen:',\n `Belege deine Antworten mit wörtlichen Zitaten: ein zusammenhängender, unveränderter Ausschnitt aus einem einzigen Block. Jedes Zitat ist ein Markdown-Link, dessen Ziel „${CITATION_HREF_PREFIX}“ gefolgt von der vollständigen ID dieses Blocks ist: [„Zitat“](${CITATION_HREF_PREFIX}ID).`,\n `Beispiel zur Zeile oben: Anna kündigt den Start an: [„Wir starten im Mai.“](${CITATION_HREF_PREFIX}${BLOCK_LINE_EXAMPLE_ID})`,\n 'Verwende nur IDs, die im Dokument vorkommen, und nenne IDs nie außerhalb solcher Links.',\n 'Steht die Antwort nicht im Dokument, sag das ehrlich, statt etwas zu erfinden.',\n 'Antworte knapp in Markdown (Absätze, Aufzählungen, **fett**) und in der Sprache der Frage.',\n '',\n 'Änderungen:',\n `Bittet die Nutzerin bzw. der Nutzer darum, das Dokument zu ändern (kürzen, umformulieren, ergänzen, löschen, umwandeln …), rufe das Werkzeug ${AGENT_TOOL} auf, statt den neuen Text im Chat zu schreiben. Schreib davor höchstens ein bis zwei Sätze dazu, was du änderst. Bei Fragen rufst du das Werkzeug nicht auf.`,\n 'Operationen: „update“ ersetzt den Inhalt des Blocks „id“ durch „markdown“; „delete“ löscht den Block „id“; „add“ fügt „markdown“ (ein oder mehrere Blöcke, durch Leerzeilen getrennt) nach dem Block „afterId“ ein („afterId“ gehört bei „add“ immer dazu, für den Dokumentanfang schreibst du ausdrücklich null; mehrere „add“ nach demselben Block werden in der Reihenfolge eingefügt, in der du sie schreibst); „convert“ wandelt den Block „id“ in den Blocktyp „to“ um.',\n `${BLOCK_LINE_ECHO_TEXT} Redebeiträge behalten den fett gesetzten Namen mit Doppelpunkt am Anfang; ein anderer Name wechselt die Sprecherin bzw. den Sprecher. Neue Redebeiträge schreibst du ebenso als „**Name:** Text“.`,\n 'Ändere nur die Blöcke, die die Bitte betrifft; lass unveränderte Blöcke weg. Jeder Block höchstens einmal; eine Operation auf einen Block innerhalb eines Blocks, den eine andere Operation ersetzt oder löscht, ist ungültig (schreibe die Änderung dann in das Markdown der äußeren Operation). Verwende nur IDs aus dem Dokument. Nennt die Nachricht einen Bearbeitungsbereich, beziehen sich alle IDs und afterIds ausschließlich auf Blöcke daraus.',\n 'Jede Änderung wird der Nutzerin bzw. dem Nutzer im Dokument zur Prüfung angezeigt und einzeln übernommen oder abgelehnt. Die Entscheidungen erhältst du mit einer späteren Nachricht („Entscheidungen zu deinen letzten Vorschlägen: …“). Geh auf abgelehnte Vorschläge ein und wiederhole sie nicht unverändert.',\n '',\n ...blockModelText(blockModel),\n ].join('\\n')\n}\n\n/** A user turn as the model reads it: decisions on earlier proposals first, then the message. */\nfunction userText(content: string, feedback: readonly AgentOpFeedback[] | undefined): string {\n const decisions = agentFeedbackText(feedback ?? [])\n return decisions ? `${decisions}\\n\\nNachricht: ${content}` : content\n}\n\n/**\n * Model messages for a chat turn: the history as sent (proposed operations as `edit_document` tool calls), with the\n * current document placed in the last (user) message next to the scope, the latest decisions and the message —\n * document content never goes into the system prompt (the editor's block model does). `scope`: IDs the edits are\n * limited to (null: whole document).\n */\nexport function documentChatMessages(messages: readonly DocumentChatMessage[], document: string, scope: readonly string[] | null, blockModel: ChatBlockModel): ModelMessage[] {\n const history = messages.slice(0, -1).flatMap((message, index): ModelMessage[] => {\n if (message.role === 'user') return [{ role: 'user', content: userText(message.content, message.feedback) }]\n if (!message.ops?.length && !message.dropped) return [{ role: 'assistant', content: message.content }]\n const ops = message.ops ?? []\n const toolCallId = `edit_${index}`\n return [\n {\n role: 'assistant',\n content: [\n ...(message.content ? [{ type: 'text' as const, text: message.content }] : []),\n { type: 'tool-call', toolCallId, toolName: AGENT_TOOL, input: { ops: ops.map(({ op: _op, ...rest }) => rest) } },\n ],\n },\n {\n role: 'tool',\n content: [{ type: 'tool-result', toolCallId, toolName: AGENT_TOOL, output: { type: 'text', value: agentShownMessage(ops, message.dropped ?? 0) } }],\n },\n ]\n })\n const last = messages.at(-1)! as Extract<DocumentChatMessage, { role: 'user' }>\n const range = scope\n ? `Bearbeitungsbereich: die Auswahl der Nutzerin bzw. des Nutzers. Änderungen (id und afterId) nur an diesen Blöcken: ${scope.join(', ')}`\n : 'Bearbeitungsbereich: das ganze Dokument.'\n const decisions = agentFeedbackText(last.feedback ?? [])\n return [\n { role: 'system', content: chatSystem(blockModel) },\n ...history,\n {\n role: 'user',\n content: [\n `${BLOCK_LINES_LABEL}:\\n\"\"\"\\n${document}\\n\"\"\"`,\n range,\n ...(decisions ? [decisions] : []),\n `Nachricht: ${last.content}`,\n ].join('\\n\\n'),\n },\n ]\n}\n"],"mappings":"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"}
|
|
@@ -66,7 +66,7 @@ export declare const generateBodySchema: z.ZodObject<{
|
|
|
66
66
|
value: z.ZodString;
|
|
67
67
|
}, z.core.$strip>>;
|
|
68
68
|
instructions: z.ZodString;
|
|
69
|
-
|
|
69
|
+
contentTemplate: z.ZodString;
|
|
70
70
|
body: z.ZodString;
|
|
71
71
|
data: z.ZodArray<z.ZodObject<{
|
|
72
72
|
label: z.ZodString;
|
|
@@ -20,7 +20,7 @@ function generateProblem(task, input) {
|
|
|
20
20
|
if (task.needsSelection && !input.selection.trim()) return "Keine Textauswahl";
|
|
21
21
|
if (task.needsPrompt && !input.prompt.trim()) return "Prompt fehlt";
|
|
22
22
|
if (task.needsLanguage && !input.language) return "Zielsprache fehlt";
|
|
23
|
-
if (task.needsBlock && !input.block) return "
|
|
23
|
+
if (task.needsBlock && !input.block) return "Block fehlt";
|
|
24
24
|
if (task.wholeDocument && !input.context.trim()) return "Dokument ist leer";
|
|
25
25
|
if (!task.wholeDocument && input.context.length > AI_LIMITS.context) return "Kontext zu lang";
|
|
26
26
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.js","names":[],"sources":["../../../../src/features/ai/protocol/generate.ts"],"sourcesContent":["// i18n-ignore-file: validation messages of the generate run (German whatever the editor's language)\nimport { z } from 'zod'\nimport type { AiStreamEvent } from '../../../core/backend'\nimport { AI_LANGUAGES } from '../../../settings/values'\nimport { modelRefSchema } from './models'\nimport { aiBlockInputSchema, aiBlockSchema } from './schemas'\nimport { AI_LIMITS, AI_TASK_IDS, type AiTask } from './tasks'\n\n/** One chat turn handed to a model. */\nexport interface ChatMessage { role: 'system' | 'user' | 'assistant', content: string }\n\n/**\n * Streams the text deltas of one chat completion for `messages` (a trailing assistant message is a prefill the model\n * continues). Aborting `signal` stops the upstream request and makes the iteration throw. The server implements it\n * with the AI SDK (`streamChat`), the browser-direct adapter with a plain `fetch`.\n */\nexport type ChatStream = (messages: ChatMessage[], signal: AbortSignal) => AsyncIterable<string>\n\n/** Body schema of the generate request (`POST /api/ai/generate`, `EditorBackend['ai'].stream('generate', …)`). */\nexport const generateBodySchema = z.object({\n task: z.enum(AI_TASK_IDS),\n prompt: z.string().max(AI_LIMITS.prompt).default(''),\n selection: z.string().max(AI_LIMITS.selection).default(''),\n // Whole-document tasks may send the longer transcript; the stricter limit for the others is checked per task in `generateProblem`.\n context: z.string().max(AI_LIMITS.transcript).default(''),\n language: z.enum(AI_LANGUAGES).optional(),\n blocks: z.array(aiBlockSchema).max(50).default([]),\n block: aiBlockInputSchema.optional(),\n model: modelRefSchema,\n})\n\n/** What a generate request carries besides the task and the model. */\nexport type GenerateInput = Omit<z.infer<typeof generateBodySchema>, 'task' | 'model'>\n\n/** Why `input` does not fit `task` (the user-facing message of a 400), or `undefined` when it does. */\nexport function generateProblem(task: AiTask, input: GenerateInput): string | undefined {\n if (task.needsSelection && !input.selection.trim()) return 'Keine Textauswahl'\n if (task.needsPrompt && !input.prompt.trim()) return 'Prompt fehlt'\n if (task.needsLanguage && !input.language) return 'Zielsprache fehlt'\n if (task.needsBlock && !input.block) return '
|
|
1
|
+
{"version":3,"file":"generate.js","names":[],"sources":["../../../../src/features/ai/protocol/generate.ts"],"sourcesContent":["// i18n-ignore-file: validation messages of the generate run (German whatever the editor's language)\nimport { z } from 'zod'\nimport type { AiStreamEvent } from '../../../core/backend'\nimport { AI_LANGUAGES } from '../../../settings/values'\nimport { modelRefSchema } from './models'\nimport { aiBlockInputSchema, aiBlockSchema } from './schemas'\nimport { AI_LIMITS, AI_TASK_IDS, type AiTask } from './tasks'\n\n/** One chat turn handed to a model. */\nexport interface ChatMessage { role: 'system' | 'user' | 'assistant', content: string }\n\n/**\n * Streams the text deltas of one chat completion for `messages` (a trailing assistant message is a prefill the model\n * continues). Aborting `signal` stops the upstream request and makes the iteration throw. The server implements it\n * with the AI SDK (`streamChat`), the browser-direct adapter with a plain `fetch`.\n */\nexport type ChatStream = (messages: ChatMessage[], signal: AbortSignal) => AsyncIterable<string>\n\n/** Body schema of the generate request (`POST /api/ai/generate`, `EditorBackend['ai'].stream('generate', …)`). */\nexport const generateBodySchema = z.object({\n task: z.enum(AI_TASK_IDS),\n prompt: z.string().max(AI_LIMITS.prompt).default(''),\n selection: z.string().max(AI_LIMITS.selection).default(''),\n // Whole-document tasks may send the longer transcript; the stricter limit for the others is checked per task in `generateProblem`.\n context: z.string().max(AI_LIMITS.transcript).default(''),\n language: z.enum(AI_LANGUAGES).optional(),\n blocks: z.array(aiBlockSchema).max(50).default([]),\n block: aiBlockInputSchema.optional(),\n model: modelRefSchema,\n})\n\n/** What a generate request carries besides the task and the model. */\nexport type GenerateInput = Omit<z.infer<typeof generateBodySchema>, 'task' | 'model'>\n\n/** Why `input` does not fit `task` (the user-facing message of a 400), or `undefined` when it does. */\nexport function generateProblem(task: AiTask, input: GenerateInput): string | undefined {\n if (task.needsSelection && !input.selection.trim()) return 'Keine Textauswahl'\n if (task.needsPrompt && !input.prompt.trim()) return 'Prompt fehlt'\n if (task.needsLanguage && !input.language) return 'Zielsprache fehlt'\n if (task.needsBlock && !input.block) return 'Block fehlt'\n if (task.wholeDocument && !input.context.trim()) return 'Dokument ist leer'\n if (!task.wholeDocument && input.context.length > AI_LIMITS.context) return 'Kontext zu lang'\n return undefined\n}\n\n/**\n * Runs one text task (rewrite, translate, generate, …) on `stream`: a `delta` (`{ text }`) per streamed chunk, then\n * `done`, or `error` (`{ message }`) when the model call fails. An aborted `signal` ends the run silently. `users` are\n * the registered usernames for tasks with `needsUsers`. The input must have passed `generateProblem`.\n */\nexport async function* runGenerate(task: AiTask, input: GenerateInput, users: readonly string[] | undefined, stream: ChatStream, signal: AbortSignal): AsyncGenerator<AiStreamEvent> {\n try {\n for await (const text of stream(task.messages({ ...input, users }), signal)) {\n yield { event: 'delta', data: { text } }\n }\n yield { event: 'done', data: {} }\n }\n catch (error) {\n if (!signal.aborted) {\n const { statusMessage, message } = error as { statusMessage?: string, message?: string }\n yield { event: 'error', data: { message: statusMessage ?? message ?? 'Unbekannter Fehler' } }\n }\n }\n}\n"],"mappings":";;;;;;;AAmBA,MAAa,qBAAqB,EAAE,OAAO;CACzC,MAAM,EAAE,KAAK,WAAW;CACxB,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,UAAU,MAAM,CAAC,CAAC,QAAQ,EAAE;CACnD,WAAW,EAAE,OAAO,CAAC,CAAC,IAAI,UAAU,SAAS,CAAC,CAAC,QAAQ,EAAE;CAEzD,SAAS,EAAE,OAAO,CAAC,CAAC,IAAI,UAAU,UAAU,CAAC,CAAC,QAAQ,EAAE;CACxD,UAAU,EAAE,KAAK,YAAY,CAAC,CAAC,SAAS;CACxC,QAAQ,EAAE,MAAM,aAAa,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;CACjD,OAAO,mBAAmB,SAAS;CACnC,OAAO;AACT,CAAC;;AAMD,SAAgB,gBAAgB,MAAc,OAA0C;CACtF,IAAI,KAAK,kBAAkB,CAAC,MAAM,UAAU,KAAK,GAAG,OAAO;CAC3D,IAAI,KAAK,eAAe,CAAC,MAAM,OAAO,KAAK,GAAG,OAAO;CACrD,IAAI,KAAK,iBAAiB,CAAC,MAAM,UAAU,OAAO;CAClD,IAAI,KAAK,cAAc,CAAC,MAAM,OAAO,OAAO;CAC5C,IAAI,KAAK,iBAAiB,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO;CACxD,IAAI,CAAC,KAAK,iBAAiB,MAAM,QAAQ,SAAS,UAAU,SAAS,OAAO;AAE9E;;;;;;AAOA,gBAAuB,YAAY,MAAc,OAAsB,OAAsC,QAAoB,QAAoD;CACnL,IAAI;EACF,WAAW,MAAM,QAAQ,OAAO,KAAK,SAAS;GAAE,GAAG;GAAO;EAAM,CAAC,GAAG,MAAM,GACxE,MAAM;GAAE,OAAO;GAAS,MAAM,EAAE,KAAK;EAAE;EAEzC,MAAM;GAAE,OAAO;GAAQ,MAAM,CAAC;EAAE;CAClC,SACO,OAAO;EACZ,IAAI,CAAC,OAAO,SAAS;GACnB,MAAM,EAAE,eAAe,YAAY;GACnC,MAAM;IAAE,OAAO;IAAS,MAAM,EAAE,SAAS,iBAAiB,WAAW,qBAAqB;GAAE;EAC9F;CACF;AACF"}
|
|
@@ -1,10 +1,10 @@
|
|
|
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 "./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 "./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 "./chat.js";
|
|
5
5
|
import { AI_LIMITS, AI_TASKS, AI_TASK_IDS, AiApplyMode, AiBlockInput, AiInput, AiMessage, AiTask, AiTaskId, blockTasks, inBlockTasks, withHeading, withTaskHeading } from "./tasks.js";
|
|
6
6
|
import { ChatMessage, ChatStream, GenerateInput, generateBodySchema, generateProblem, runGenerate } from "./generate.js";
|
|
7
7
|
import { AI_COMPLETE_LIMITS, AiCompleteMessage, cleanCompletion, completeBodySchema, completeMessages, completionReady, runCompletion } from "./complete.js";
|
|
8
|
-
import { AI_LANGUAGE_KEYS, MODEL_REF_LIMITS,
|
|
8
|
+
import { AI_LANGUAGE_KEYS, MODEL_REF_LIMITS, MODEL_ROLE_KEYS, UserModelProfile, modelRefSchema } from "./models.js";
|
|
9
9
|
import { AI_ID_PATTERN, aiBlockInputSchema, aiBlockSchema } from "./schemas.js";
|
|
10
|
-
export { AGENT_LIMITS, AGENT_OP_OUTCOMES, AGENT_OP_OUTCOME_TEXT, AGENT_OP_TYPES, AGENT_TOOL, AI_COMPLETE_LIMITS, AI_ID_PATTERN, AI_LANGUAGE_KEYS, AI_LIMITS, AI_TASKS, AI_TASK_IDS, AgentOp, AgentOpContext, AgentOpFeedback, AgentOpOutcome, AgentOpProblem, AgentOpProblemReason, AgentOpType, AgentTextOptions, AiApplyMode, AiBlockInput, AiCompleteMessage, AiInput, AiMessage, AiTask, AiTaskId, BLOCK_LINES_LABEL, BLOCK_LINE_COMPOSITE_TEXT, BLOCK_LINE_ECHO_TEXT, BLOCK_LINE_EXAMPLE, BLOCK_LINE_EXAMPLE_ID, BLOCK_LINE_EXAMPLE_TEXT, BLOCK_LINE_HOST_TEXT, BLOCK_LINE_IDS_HINT, BLOCK_LINE_INTRO, BLOCK_LINE_LIST_TEXT, BLOCK_LINE_MARKERS, BlockLines, CHAT_LIMITS, CITATION_HREF_PREFIX, ChatBlock, ChatBlockModel,
|
|
10
|
+
export { AGENT_LIMITS, AGENT_OP_OUTCOMES, AGENT_OP_OUTCOME_TEXT, AGENT_OP_TYPES, AGENT_TOOL, AI_COMPLETE_LIMITS, AI_ID_PATTERN, AI_LANGUAGE_KEYS, AI_LIMITS, AI_TASKS, AI_TASK_IDS, AgentOp, AgentOpContext, AgentOpFeedback, AgentOpOutcome, AgentOpProblem, AgentOpProblemReason, AgentOpType, AgentTextOptions, AiApplyMode, AiBlockInput, AiCompleteMessage, AiInput, AiMessage, AiTask, AiTaskId, BLOCK_LINES_LABEL, BLOCK_LINE_COMPOSITE_TEXT, BLOCK_LINE_ECHO_TEXT, BLOCK_LINE_EXAMPLE, BLOCK_LINE_EXAMPLE_ID, BLOCK_LINE_EXAMPLE_TEXT, BLOCK_LINE_HOST_TEXT, BLOCK_LINE_IDS_HINT, BLOCK_LINE_INTRO, BLOCK_LINE_LIST_TEXT, BLOCK_LINE_MARKERS, BlockLines, CHAT_LIMITS, CITATION_HREF_PREFIX, ChatBlock, ChatBlockModel, ChatBlockType, ChatMessage, ChatStream, DocumentChatMessage, GenerateInput, MODEL_REF_LIMITS, MODEL_ROLE_KEYS, ModelAgentOp, type ModelProfile, type ModelRef, TRUNCATED_LINE, UserModelProfile, agentFeedbackText, agentOpSummary, agentOpTarget, agentRetryMessage, agentShownMessage, agentUnreadableProblem, aiBlockInputSchema, aiBlockSchema, blockLine, blockTasks, checkAgentOps, citationBlockId, cleanCompletion, completeBodySchema, completeMessages, completionReady, compositeChromePart, compositeLineClose, compositeLineHeader, continuedLinePrefix, documentChatMessages, generateBodySchema, generateProblem, inBlockTasks, listLinePrefix, modelRefSchema, nestedLinePrefix, quoteLinePrefix, readBlockLines, runCompletion, runGenerate, singleBlockLine, 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 "./models.js";
|
|
2
2
|
import { AI_COMPLETE_LIMITS, cleanCompletion, completeBodySchema, completeMessages, completionReady, runCompletion } from "./complete.js";
|
|
3
3
|
import { AI_LIMITS, AI_TASKS, AI_TASK_IDS, blockTasks, inBlockTasks, withHeading, withTaskHeading } from "./tasks.js";
|
|
4
4
|
import { AI_ID_PATTERN, aiBlockInputSchema, aiBlockSchema } from "./schemas.js";
|
|
@@ -6,4 +6,4 @@ import { generateBodySchema, generateProblem, runGenerate } from "./generate.js"
|
|
|
6
6
|
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, TRUNCATED_LINE, blockLine, compositeChromePart, compositeLineClose, compositeLineHeader, continuedLinePrefix, listLinePrefix, nestedLinePrefix, quoteLinePrefix, readBlockLines, singleBlockLine, stripBlockLineEcho, stripListMarkerEcho } from "./block-lines.js";
|
|
7
7
|
import { AGENT_LIMITS, AGENT_OP_OUTCOMES, AGENT_OP_OUTCOME_TEXT, AGENT_OP_TYPES, AGENT_TOOL, agentFeedbackText, agentOpSummary, agentOpTarget, agentRetryMessage, agentShownMessage, agentUnreadableProblem, checkAgentOps } from "./agent-ops.js";
|
|
8
8
|
import { CHAT_LIMITS, CITATION_HREF_PREFIX, citationBlockId, documentChatMessages } from "./chat.js";
|
|
9
|
-
export { AGENT_LIMITS, AGENT_OP_OUTCOMES, AGENT_OP_OUTCOME_TEXT, AGENT_OP_TYPES, AGENT_TOOL, AI_COMPLETE_LIMITS, AI_ID_PATTERN, AI_LANGUAGE_KEYS, AI_LIMITS, AI_TASKS, AI_TASK_IDS, 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,
|
|
9
|
+
export { AGENT_LIMITS, AGENT_OP_OUTCOMES, AGENT_OP_OUTCOME_TEXT, AGENT_OP_TYPES, AGENT_TOOL, AI_COMPLETE_LIMITS, AI_ID_PATTERN, AI_LANGUAGE_KEYS, AI_LIMITS, AI_TASKS, AI_TASK_IDS, 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, agentFeedbackText, agentOpSummary, agentOpTarget, agentRetryMessage, agentShownMessage, agentUnreadableProblem, aiBlockInputSchema, aiBlockSchema, blockLine, blockTasks, checkAgentOps, citationBlockId, cleanCompletion, completeBodySchema, completeMessages, completionReady, compositeChromePart, compositeLineClose, compositeLineHeader, continuedLinePrefix, documentChatMessages, generateBodySchema, generateProblem, inBlockTasks, listLinePrefix, modelRefSchema, nestedLinePrefix, quoteLinePrefix, readBlockLines, runCompletion, runGenerate, singleBlockLine, stripBlockLineEcho, stripListMarkerEcho, withHeading, withTaskHeading };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { MessageKey } from "../../../i18n/index.js";
|
|
2
|
-
import { AiLanguage,
|
|
2
|
+
import { AiLanguage, ModelRole } from "../../../settings/values.js";
|
|
3
3
|
import "../../../settings/index.js";
|
|
4
4
|
import { ModelProfile, ModelRef } from "../../../core/backend-types.js";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
//#region src/features/ai/protocol/models.d.ts
|
|
7
|
-
/** Catalog keys of the label and description of each
|
|
8
|
-
export declare const
|
|
7
|
+
/** Catalog keys of the label and description of each Model role for the settings UI. */
|
|
8
|
+
export declare const MODEL_ROLE_KEYS: Record<ModelRole, {
|
|
9
9
|
labelKey: MessageKey;
|
|
10
10
|
descriptionKey: MessageKey;
|
|
11
11
|
}>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
//#region src/features/ai/protocol/models.ts
|
|
3
|
-
/** Catalog keys of the label and description of each
|
|
4
|
-
const
|
|
3
|
+
/** Catalog keys of the label and description of each Model role for the settings UI. */
|
|
4
|
+
const MODEL_ROLE_KEYS = {
|
|
5
5
|
complete: {
|
|
6
6
|
labelKey: "ai.slot.complete.label",
|
|
7
7
|
descriptionKey: "ai.slot.complete.description"
|
|
@@ -36,6 +36,6 @@ const modelRefSchema = z.union([z.object({ preset: z.string().min(1).max(100) })
|
|
|
36
36
|
apiKey: z.string().min(1).max(MODEL_REF_LIMITS.apiKey)
|
|
37
37
|
})]);
|
|
38
38
|
//#endregion
|
|
39
|
-
export { AI_LANGUAGE_KEYS, MODEL_REF_LIMITS,
|
|
39
|
+
export { AI_LANGUAGE_KEYS, MODEL_REF_LIMITS, MODEL_ROLE_KEYS, modelRefSchema };
|
|
40
40
|
|
|
41
41
|
//# sourceMappingURL=models.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models.js","names":[],"sources":["../../../../src/features/ai/protocol/models.ts"],"sourcesContent":["import type { ModelProfile, ModelRef } from '../../../core/backend-types'\nimport type { MessageKey } from '../../../i18n'\nimport type { AiLanguage,
|
|
1
|
+
{"version":3,"file":"models.js","names":[],"sources":["../../../../src/features/ai/protocol/models.ts"],"sourcesContent":["import type { ModelProfile, ModelRef } from '../../../core/backend-types'\nimport type { MessageKey } from '../../../i18n'\nimport type { AiLanguage, ModelRole } from '../../../settings'\nimport { z } from 'zod'\n\n/** Catalog keys of the label and description of each Model role for the settings UI. */\nexport const MODEL_ROLE_KEYS: Record<ModelRole, { labelKey: MessageKey, descriptionKey: MessageKey }> = {\n complete: { labelKey: 'ai.slot.complete.label', descriptionKey: 'ai.slot.complete.description' },\n rewrite: { labelKey: 'ai.slot.rewrite.label', descriptionKey: 'ai.slot.rewrite.description' },\n generate: { labelKey: 'ai.slot.generate.label', descriptionKey: 'ai.slot.generate.description' },\n}\n\n/** Catalog keys of the display names of the stored target-language ids (`AI_LANGUAGES`); the stored id is what the model is told. */\nexport const AI_LANGUAGE_KEYS: Record<AiLanguage, MessageKey> = {\n Deutsch: 'ai.language.de',\n Englisch: 'ai.language.en',\n Französisch: 'ai.language.fr',\n Spanisch: 'ai.language.es',\n Italienisch: 'ai.language.it',\n}\n\n// `ModelProfile` (a profile as the client sees it; Model presets never expose their key) and `ModelRef` (the model an AI\n// request runs on: a Model preset by id, or an OpenAI-compatible endpoint with its own key) are core's, because\n// `EditorBackend.ai` names them; this entry exports them as before.\nexport type { ModelProfile, ModelRef }\n\n/** Browser-defined profile: its key is sent with each request and never stored on the server. */\nexport interface UserModelProfile extends Omit<ModelProfile, 'source'> { apiKey: string }\n\n/** Maximum lengths (characters) of the fields of a user `ModelRef`. */\nexport const MODEL_REF_LIMITS = { endpoint: 500, model: 200, apiKey: 500 } as const\n\n/** Validates the `model` field every AI route requires in its body. */\nexport const modelRefSchema = z.union([\n z.object({ preset: z.string().min(1).max(100) }),\n z.object({\n endpoint: z.string().url().max(MODEL_REF_LIMITS.endpoint),\n model: z.string().min(1).max(MODEL_REF_LIMITS.model),\n apiKey: z.string().min(1).max(MODEL_REF_LIMITS.apiKey),\n }),\n]) satisfies z.ZodType<ModelRef>\n"],"mappings":";;;AAMA,MAAa,kBAA2F;CACtG,UAAU;EAAE,UAAU;EAA0B,gBAAgB;CAA+B;CAC/F,SAAS;EAAE,UAAU;EAAyB,gBAAgB;CAA8B;CAC5F,UAAU;EAAE,UAAU;EAA0B,gBAAgB;CAA+B;AACjG;;AAGA,MAAa,mBAAmD;CAC9D,SAAS;CACT,UAAU;CACV,aAAa;CACb,UAAU;CACV,aAAa;AACf;;AAWA,MAAa,mBAAmB;CAAE,UAAU;CAAK,OAAO;CAAK,QAAQ;AAAI;;AAGzE,MAAa,iBAAiB,EAAE,MAAM,CACpC,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,GAC/C,EAAE,OAAO;CACP,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,iBAAiB,QAAQ;CACxD,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,iBAAiB,KAAK;CACnD,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,iBAAiB,MAAM;AACvD,CAAC,CACH,CAAC"}
|
|
@@ -25,7 +25,7 @@ export declare const aiBlockInputSchema: z.ZodObject<{
|
|
|
25
25
|
value: z.ZodString;
|
|
26
26
|
}, z.core.$strip>>;
|
|
27
27
|
instructions: z.ZodString;
|
|
28
|
-
|
|
28
|
+
contentTemplate: z.ZodString;
|
|
29
29
|
body: z.ZodString;
|
|
30
30
|
data: z.ZodArray<z.ZodObject<{
|
|
31
31
|
label: z.ZodString;
|
|
@@ -27,7 +27,7 @@ const aiBlockInputSchema = z.object({
|
|
|
27
27
|
value: shortText(2e3)
|
|
28
28
|
})).max(20),
|
|
29
29
|
instructions: shortText(AI_LIMITS.block.text),
|
|
30
|
-
|
|
30
|
+
contentTemplate: shortText(AI_LIMITS.block.contentTemplate),
|
|
31
31
|
body: shortText(AI_LIMITS.block.body),
|
|
32
32
|
data: z.array(z.object({
|
|
33
33
|
label: z.string().min(1).max(100),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.js","names":[],"sources":["../../../../src/features/ai/protocol/schemas.ts"],"sourcesContent":["import { z } from 'zod'\nimport type { AiBlock } from '../../../core/feature'\nimport { AI_LIMITS } from './tasks'\n\n/** Characters of a node type name, `convert` target id and `::: kind` fence opener. */\nexport const AI_ID_PATTERN = /^[\\p{L}\\p{N}_-]+$/u\n\n/** A host block from `aiContext.blocks`, as the AI routes accept it. */\nexport const aiBlockSchema = z.object({\n id: z.string().regex(AI_ID_PATTERN).max(50),\n label: z.string().min(1).max(100),\n description: z.string().min(1).max(500),\n syntax: z.string().min(1).max(500),\n example: z.string().min(1).max(1000),\n}) satisfies z.ZodType<AiBlock>\n\nconst shortText = (max: number) => z.string().max(max)\n\n/** The block of a `fill-block` run (`AiBlockInput`), as the generate route accepts it. */\nexport const aiBlockInputSchema = z.object({\n kind: z.object({ id: z.string().regex(AI_ID_PATTERN).max(50), label: z.string().min(1).max(100), purpose: z.string().max(500).optional() }),\n path: z.array(shortText(200)).max(20),\n title: shortText(500),\n description: shortText(2000),\n fields: z.array(z.object({ label: z.string().min(1).max(100), value: shortText(2000) })).max(20),\n instructions: shortText(AI_LIMITS.block.text),\n
|
|
1
|
+
{"version":3,"file":"schemas.js","names":[],"sources":["../../../../src/features/ai/protocol/schemas.ts"],"sourcesContent":["import { z } from 'zod'\nimport type { AiBlock } from '../../../core/feature'\nimport { AI_LIMITS } from './tasks'\n\n/** Characters of a node type name, `convert` target id and `::: kind` fence opener. */\nexport const AI_ID_PATTERN = /^[\\p{L}\\p{N}_-]+$/u\n\n/** A host block from `aiContext.blocks`, as the AI routes accept it. */\nexport const aiBlockSchema = z.object({\n id: z.string().regex(AI_ID_PATTERN).max(50),\n label: z.string().min(1).max(100),\n description: z.string().min(1).max(500),\n syntax: z.string().min(1).max(500),\n example: z.string().min(1).max(1000),\n}) satisfies z.ZodType<AiBlock>\n\nconst shortText = (max: number) => z.string().max(max)\n\n/** The block of a `fill-block` run (`AiBlockInput`), as the generate route accepts it. */\nexport const aiBlockInputSchema = z.object({\n kind: z.object({ id: z.string().regex(AI_ID_PATTERN).max(50), label: z.string().min(1).max(100), purpose: z.string().max(500).optional() }),\n path: z.array(shortText(200)).max(20),\n title: shortText(500),\n description: shortText(2000),\n fields: z.array(z.object({ label: z.string().min(1).max(100), value: shortText(2000) })).max(20),\n instructions: shortText(AI_LIMITS.block.text),\n contentTemplate: shortText(AI_LIMITS.block.contentTemplate),\n body: shortText(AI_LIMITS.block.body),\n data: z.array(z.object({ label: z.string().min(1).max(100), text: shortText(AI_LIMITS.block.data) })).max(10),\n})\n"],"mappings":";;;;AAKA,MAAa,gBAAgB;;AAG7B,MAAa,gBAAgB,EAAE,OAAO;CACpC,IAAI,EAAE,OAAO,CAAC,CAAC,MAAM,aAAa,CAAC,CAAC,IAAI,EAAE;CAC1C,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG;CAChC,aAAa,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG;CACtC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG;CACjC,SAAS,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAI;AACrC,CAAC;AAED,MAAM,aAAa,QAAgB,EAAE,OAAO,CAAC,CAAC,IAAI,GAAG;;AAGrD,MAAa,qBAAqB,EAAE,OAAO;CACzC,MAAM,EAAE,OAAO;EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,MAAM,aAAa,CAAC,CAAC,IAAI,EAAE;EAAG,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG;EAAG,SAAS,EAAE,OAAO,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,SAAS;CAAE,CAAC;CAC1I,MAAM,EAAE,MAAM,UAAU,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE;CACpC,OAAO,UAAU,GAAG;CACpB,aAAa,UAAU,GAAI;CAC3B,QAAQ,EAAE,MAAM,EAAE,OAAO;EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG;EAAG,OAAO,UAAU,GAAI;CAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;CAC/F,cAAc,UAAU,UAAU,MAAM,IAAI;CAC5C,iBAAiB,UAAU,UAAU,MAAM,eAAe;CAC1D,MAAM,UAAU,UAAU,MAAM,IAAI;CACpC,MAAM,EAAE,MAAM,EAAE,OAAO;EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG;EAAG,MAAM,UAAU,UAAU,MAAM,IAAI;CAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AAC9G,CAAC"}
|
|
@@ -25,7 +25,7 @@ export interface AiBlockInput {
|
|
|
25
25
|
value: string;
|
|
26
26
|
}[];
|
|
27
27
|
instructions: string;
|
|
28
|
-
|
|
28
|
+
contentTemplate: string;
|
|
29
29
|
body: string;
|
|
30
30
|
data: readonly {
|
|
31
31
|
label: string;
|
|
@@ -59,7 +59,7 @@ export interface AiTask {
|
|
|
59
59
|
/** Catalog key of the input placeholder of a task with `needsPrompt`; the other tasks name an optional hint. */
|
|
60
60
|
promptLabelKey?: MessageKey;
|
|
61
61
|
apply: AiApplyMode;
|
|
62
|
-
/** Model
|
|
62
|
+
/** Model role the task runs on: `rewrite` (in-block AI, text inside one block) or `generate` (block generation). */
|
|
63
63
|
slot: 'rewrite' | 'generate';
|
|
64
64
|
/** The context is the whole document (up to `AI_LIMITS.transcript`) and must not be empty. */
|
|
65
65
|
wholeDocument?: boolean;
|
|
@@ -95,15 +95,15 @@ export declare const AI_LIMITS: {
|
|
|
95
95
|
readonly transcript: 60000;
|
|
96
96
|
readonly block: {
|
|
97
97
|
readonly text: 4000;
|
|
98
|
-
readonly
|
|
98
|
+
readonly contentTemplate: 8000;
|
|
99
99
|
readonly body: 20000;
|
|
100
100
|
readonly data: 20000;
|
|
101
101
|
};
|
|
102
102
|
};
|
|
103
103
|
export declare const AI_TASKS: Record<AiTaskId, AiTask>;
|
|
104
|
-
/** In-block AI tasks (`rewrite`
|
|
104
|
+
/** In-block AI tasks (`rewrite` Model role): rewrite text inside one block or a selection. */
|
|
105
105
|
export declare const inBlockTasks: () => AiTask[];
|
|
106
|
-
/** Block generation tasks (`generate`
|
|
106
|
+
/** Block generation tasks (`generate` Model role): produce new blocks after the caret or at the end of the document. */
|
|
107
107
|
export declare const blockTasks: () => AiTask[];
|
|
108
108
|
//#endregion
|
|
109
109
|
//# sourceMappingURL=tasks.d.ts.map
|
|
@@ -34,7 +34,7 @@ const AI_LIMITS = {
|
|
|
34
34
|
transcript: 6e4,
|
|
35
35
|
block: {
|
|
36
36
|
text: 4e3,
|
|
37
|
-
|
|
37
|
+
contentTemplate: 8e3,
|
|
38
38
|
body: 2e4,
|
|
39
39
|
data: 2e4
|
|
40
40
|
}
|
|
@@ -206,17 +206,17 @@ const AI_TASKS = {
|
|
|
206
206
|
}, {
|
|
207
207
|
role: "user",
|
|
208
208
|
content: [
|
|
209
|
-
`Schreibe den Inhalt des
|
|
210
|
-
...block.path.length ? [`Der
|
|
211
|
-
...block.description.trim() ? [`Beschreibung des
|
|
212
|
-
...block.fields.length ? [`Angaben zum
|
|
209
|
+
`Schreibe den Inhalt des Blocks „${block.title || block.kind.label}“ (Blocktyp: ${block.kind.label}${block.kind.purpose ? ` – ${block.kind.purpose}` : ""}).`,
|
|
210
|
+
...block.path.length ? [`Der Block steht unter: ${block.path.join(" › ")}.`] : [],
|
|
211
|
+
...block.description.trim() ? [`Beschreibung des Blocks: ${block.description.trim()}`] : [],
|
|
212
|
+
...block.fields.length ? [`Angaben zum Block:\n${block.fields.map((f) => `- ${f.label}: ${f.value}`).join("\n")}`] : [],
|
|
213
213
|
...block.instructions.trim() ? [`Anweisung: ${block.instructions.trim()}`] : [],
|
|
214
|
-
...block.
|
|
214
|
+
...block.contentTemplate.trim() ? [`Zieltext (Inhaltsvorlage; Platzhalter in geschweiften Klammern ausfüllen, Struktur und Reihenfolge beibehalten):\n"""\n${block.contentTemplate.trim()}\n"""`] : [],
|
|
215
215
|
...block.data.map((d) => `${d.label}:\n"""\n${d.text}\n"""`),
|
|
216
|
-
...block.body.trim() ? [`Bisheriger Inhalt des
|
|
216
|
+
...block.body.trim() ? [`Bisheriger Inhalt des Blocks (wird ersetzt; Brauchbares übernehmen):\n"""\n${block.body.trim()}\n"""`] : [],
|
|
217
217
|
...prompt.trim() ? [`Hinweis: ${prompt.trim()}`] : [],
|
|
218
218
|
contextBlock(context),
|
|
219
|
-
"Gib nur die Inhaltsblöcke des
|
|
219
|
+
"Gib nur die Inhaltsblöcke des Blocks als Markdown zurück: keine Titelzeile, keine Felder, keinen :::-Zaun."
|
|
220
220
|
].join("\n\n")
|
|
221
221
|
}]
|
|
222
222
|
},
|
|
@@ -268,7 +268,7 @@ const AI_TASKS = {
|
|
|
268
268
|
content: aiSystem(blocks)
|
|
269
269
|
}, {
|
|
270
270
|
role: "user",
|
|
271
|
-
content: ["Fasse den folgenden
|
|
271
|
+
content: ["Fasse den folgenden Block knapp in ein bis drei Absätzen zusammen. Behalte Fachbegriffe bei. Gib nur die Zusammenfassung als Markdown zurück, ohne Überschrift.", `Block:\n"""\n${selection}\n"""`].join("\n\n")
|
|
272
272
|
}]
|
|
273
273
|
},
|
|
274
274
|
"transfer-bullets": {
|
|
@@ -285,13 +285,13 @@ const AI_TASKS = {
|
|
|
285
285
|
content: aiSystem(blocks)
|
|
286
286
|
}, {
|
|
287
287
|
role: "user",
|
|
288
|
-
content: ["Gib die Kernaussagen des folgenden
|
|
288
|
+
content: ["Gib die Kernaussagen des folgenden Blocks als Aufzählung zurück: eine Markdown-Liste, ein Punkt je Aussage, knapp und vollständig. Gib nur die Liste zurück, ohne Überschrift.", `Block:\n"""\n${selection}\n"""`].join("\n\n")
|
|
289
289
|
}]
|
|
290
290
|
}
|
|
291
291
|
};
|
|
292
|
-
/** In-block AI tasks (`rewrite`
|
|
292
|
+
/** In-block AI tasks (`rewrite` Model role): rewrite text inside one block or a selection. */
|
|
293
293
|
const inBlockTasks = () => Object.values(AI_TASKS).filter((task) => task.slot === "rewrite");
|
|
294
|
-
/** Block generation tasks (`generate`
|
|
294
|
+
/** Block generation tasks (`generate` Model role): produce new blocks after the caret or at the end of the document. */
|
|
295
295
|
const blockTasks = () => Object.values(AI_TASKS).filter((task) => task.slot === "generate" && !task.needsBlock && !task.programmatic);
|
|
296
296
|
//#endregion
|
|
297
297
|
export { AI_LIMITS, AI_TASKS, AI_TASK_IDS, blockTasks, inBlockTasks, withHeading, withTaskHeading };
|