@elytracms/studio 0.0.91 → 0.0.93
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/convex/asset-alt-migration.test.ts +127 -0
- package/convex/asset-replace.test.ts +168 -0
- package/convex/asset-revalidate.test.ts +6 -6
- package/convex/assets.ts +41 -5
- package/convex/cms.ts +537 -177
- package/convex/contract-parity.test.ts +173 -19
- package/convex/delivery.ts +26 -13
- package/convex/document-revalidate.test.ts +17 -16
- package/convex/orphan-hydration.test.ts +116 -0
- package/convex/presence-cost.test.ts +89 -0
- package/convex/rail-write-parity.test.ts +17 -14
- package/convex/referenceMaintenance.ts +15 -15
- package/convex/schema.ts +70 -5
- package/convex/triggers.ts +21 -8
- package/convex/write-limits.ts +1 -1
- package/dist/components/ai/ai-chat-panel.js +33 -22
- package/dist/components/ai/ai-chat-panel.js.map +1 -1
- package/dist/components/ai/proposal-card.js +2 -1
- package/dist/components/ai/proposal-card.js.map +1 -1
- package/dist/components/ai/translate-document-action.d.ts +8 -2
- package/dist/components/ai/translate-document-action.js.map +1 -1
- package/dist/components/ai/translate-document-dialog.d.ts +1 -1
- package/dist/components/ai/translate-document-dialog.js +14 -8
- package/dist/components/ai/translate-document-dialog.js.map +1 -1
- package/dist/components/ai/translate-skipped.d.ts +19 -0
- package/dist/components/ai/translate-skipped.js +46 -0
- package/dist/components/ai/translate-skipped.js.map +1 -0
- package/dist/components/app-views/default-modules.d.ts +23 -6
- package/dist/components/app-views/default-modules.js +33 -14
- package/dist/components/app-views/default-modules.js.map +1 -1
- package/dist/components/assets/asset-detail.js +18 -8
- package/dist/components/assets/asset-detail.js.map +1 -1
- package/dist/components/assets/asset-metadata.d.ts +15 -4
- package/dist/components/assets/asset-metadata.js +15 -2
- package/dist/components/assets/asset-metadata.js.map +1 -1
- package/dist/components/assets/asset-search.js +4 -1
- package/dist/components/assets/asset-search.js.map +1 -1
- package/dist/components/assets/asset-selection.d.ts +0 -8
- package/dist/components/assets/asset-selection.js +4 -23
- package/dist/components/assets/asset-selection.js.map +1 -1
- package/dist/components/assets/asset-thumb.js +3 -2
- package/dist/components/assets/asset-thumb.js.map +1 -1
- package/dist/components/assets/assets-collection-view-source.d.ts +3 -3
- package/dist/components/assets/assets-collection-view-source.js +9 -5
- package/dist/components/assets/assets-collection-view-source.js.map +1 -1
- package/dist/components/assets/assets-store.d.ts +14 -0
- package/dist/components/assets/assets-store.js +23 -1
- package/dist/components/assets/assets-store.js.map +1 -1
- package/dist/components/assets/replace-file.d.ts +22 -0
- package/dist/components/assets/replace-file.js +59 -0
- package/dist/components/assets/replace-file.js.map +1 -0
- package/dist/components/builder/blocks-model.d.ts +14 -26
- package/dist/components/builder/blocks-model.js +35 -41
- package/dist/components/builder/blocks-model.js.map +1 -1
- package/dist/components/builder/blocks-panel.d.ts +7 -3
- package/dist/components/builder/blocks-panel.js +6 -5
- package/dist/components/builder/blocks-panel.js.map +1 -1
- package/dist/components/builder/builder-store.d.ts +126 -30
- package/dist/components/builder/builder-store.js +169 -67
- package/dist/components/builder/builder-store.js.map +1 -1
- package/dist/components/builder/canvas-body.d.ts +30 -0
- package/dist/components/builder/canvas-body.js +38 -0
- package/dist/components/builder/canvas-body.js.map +1 -0
- package/dist/components/builder/canvas-chrome-css.js +7 -0
- package/dist/components/builder/canvas-chrome-css.js.map +1 -1
- package/dist/components/builder/canvas-dnd.d.ts +7 -7
- package/dist/components/builder/canvas-dnd.js +5 -5
- package/dist/components/builder/canvas-dnd.js.map +1 -1
- package/dist/components/builder/canvas-render-context.d.ts +30 -22
- package/dist/components/builder/canvas-render-context.js +44 -44
- package/dist/components/builder/canvas-render-context.js.map +1 -1
- package/dist/components/builder/canvas-runs.d.ts +45 -0
- package/dist/components/builder/canvas-runs.js +51 -0
- package/dist/components/builder/canvas-runs.js.map +1 -0
- package/dist/components/builder/canvas.d.ts +5 -4
- package/dist/components/builder/canvas.js +34 -6
- package/dist/components/builder/canvas.js.map +1 -1
- package/dist/components/builder/clipboard-actions.d.ts +15 -0
- package/dist/components/builder/clipboard-actions.js +50 -13
- package/dist/components/builder/clipboard-actions.js.map +1 -1
- package/dist/components/builder/composition-field-editor.d.ts +10 -16
- package/dist/components/builder/composition-field-editor.js +30 -40
- package/dist/components/builder/composition-field-editor.js.map +1 -1
- package/dist/components/builder/composition-patches.d.ts +7 -0
- package/dist/components/builder/composition-patches.js +256 -0
- package/dist/components/builder/composition-patches.js.map +1 -0
- package/dist/components/builder/delete-key.d.ts +5 -0
- package/dist/components/builder/delete-key.js +4 -0
- package/dist/components/builder/delete-key.js.map +1 -1
- package/dist/components/builder/insert-context.d.ts +17 -25
- package/dist/components/builder/insert-context.js +45 -92
- package/dist/components/builder/insert-context.js.map +1 -1
- package/dist/components/builder/page-tree.d.ts +3 -3
- package/dist/components/builder/page-tree.js +3 -3
- package/dist/components/builder/page-tree.js.map +1 -1
- package/dist/components/builder/placement-refusal.d.ts +18 -0
- package/dist/components/builder/placement-refusal.js +46 -0
- package/dist/components/builder/placement-refusal.js.map +1 -0
- package/dist/components/builder/property-inspector.js +4 -0
- package/dist/components/builder/property-inspector.js.map +1 -1
- package/dist/components/builder/reuse-context.js +65 -26
- package/dist/components/builder/reuse-context.js.map +1 -1
- package/dist/components/builder/reuse.d.ts +79 -8
- package/dist/components/builder/reuse.js +71 -23
- package/dist/components/builder/reuse.js.map +1 -1
- package/dist/components/builder/run-inspector.d.ts +11 -0
- package/dist/components/builder/run-inspector.js +33 -0
- package/dist/components/builder/run-inspector.js.map +1 -0
- package/dist/components/cms/asset-field.d.ts +38 -1
- package/dist/components/cms/asset-field.js +182 -58
- package/dist/components/cms/asset-field.js.map +1 -1
- package/dist/components/cms/asset-picker-core.d.ts +16 -0
- package/dist/components/cms/asset-picker-core.js +20 -0
- package/dist/components/cms/asset-picker-core.js.map +1 -1
- package/dist/components/cms/asset-picker.js +12 -18
- package/dist/components/cms/asset-picker.js.map +1 -1
- package/dist/components/cms/bulk-actions.d.ts +4 -20
- package/dist/components/cms/bulk-actions.js +3 -24
- package/dist/components/cms/bulk-actions.js.map +1 -1
- package/dist/components/cms/cell-edit.d.ts +5 -5
- package/dist/components/cms/cell-edit.js.map +1 -1
- package/dist/components/cms/cell.js.map +1 -1
- package/dist/components/cms/cms-store.d.ts +87 -45
- package/dist/components/cms/cms-store.js +347 -203
- package/dist/components/cms/cms-store.js.map +1 -1
- package/dist/components/cms/collection-table.js +7 -2
- package/dist/components/cms/collection-table.js.map +1 -1
- package/dist/components/cms/commit-policy.d.ts +24 -0
- package/dist/components/cms/commit-policy.js +37 -0
- package/dist/components/cms/commit-policy.js.map +1 -0
- package/dist/components/cms/detail-editor.js +83 -137
- package/dist/components/cms/detail-editor.js.map +1 -1
- package/dist/components/cms/document-diff-view.d.ts +3 -1
- package/dist/components/cms/document-diff-view.js +12 -7
- package/dist/components/cms/document-diff-view.js.map +1 -1
- package/dist/components/cms/draft-commit.d.ts +70 -0
- package/dist/components/cms/draft-commit.js +82 -0
- package/dist/components/cms/draft-commit.js.map +1 -0
- package/dist/components/cms/duplicate-document.d.ts +11 -13
- package/dist/components/cms/duplicate-document.js +26 -34
- package/dist/components/cms/duplicate-document.js.map +1 -1
- package/dist/components/cms/field-anchors.d.ts +7 -4
- package/dist/components/cms/field-anchors.js +9 -7
- package/dist/components/cms/field-anchors.js.map +1 -1
- package/dist/components/cms/field-collaboration.d.ts +47 -0
- package/dist/components/cms/field-collaboration.js +87 -0
- package/dist/components/cms/field-collaboration.js.map +1 -0
- package/dist/components/cms/field-control-lib.d.ts +22 -1
- package/dist/components/cms/field-control-lib.js +33 -4
- package/dist/components/cms/field-control-lib.js.map +1 -1
- package/dist/components/cms/field-control.js +17 -14
- package/dist/components/cms/field-control.js.map +1 -1
- package/dist/components/cms/gate-validation.d.ts +21 -30
- package/dist/components/cms/gate-validation.js +11 -22
- package/dist/components/cms/gate-validation.js.map +1 -1
- package/dist/components/cms/object-array-field.js +4 -4
- package/dist/components/cms/object-array-field.js.map +1 -1
- package/dist/components/cms/prop-fields.d.ts +7 -2
- package/dist/components/cms/prop-fields.js +13 -6
- package/dist/components/cms/prop-fields.js.map +1 -1
- package/dist/components/cms/reference-confirm.js +10 -4
- package/dist/components/cms/reference-confirm.js.map +1 -1
- package/dist/components/cms/rich-text/embed-picker.d.ts +1 -1
- package/dist/components/cms/rich-text/embed-picker.js.map +1 -1
- package/dist/components/cms/rich-text/insert.d.ts +20 -9
- package/dist/components/cms/rich-text/insert.js +25 -17
- package/dist/components/cms/rich-text/insert.js.map +1 -1
- package/dist/components/cms/use-document-draft.d.ts +96 -0
- package/dist/components/cms/use-document-draft.js +283 -0
- package/dist/components/cms/use-document-draft.js.map +1 -0
- package/dist/components/cms/use-document-versions.js +2 -2
- package/dist/components/cms/use-document-versions.js.map +1 -1
- package/dist/components/cms/use-live-url.d.ts +6 -12
- package/dist/components/cms/use-live-url.js +16 -15
- package/dist/components/cms/use-live-url.js.map +1 -1
- package/dist/components/cms/use-publish-controller.d.ts +13 -18
- package/dist/components/cms/use-publish-controller.js +24 -41
- package/dist/components/cms/use-publish-controller.js.map +1 -1
- package/dist/components/cms/use-published-perspective.d.ts +2 -3
- package/dist/components/cms/use-published-perspective.js +4 -3
- package/dist/components/cms/use-published-perspective.js.map +1 -1
- package/dist/components/cms/versions-pane.js +8 -1
- package/dist/components/cms/versions-pane.js.map +1 -1
- package/dist/components/collection-view/cms-collection-view-source.js +24 -7
- package/dist/components/collection-view/cms-collection-view-source.js.map +1 -1
- package/dist/components/components/transfer-dialog.js +28 -23
- package/dist/components/components/transfer-dialog.js.map +1 -1
- package/dist/components/components/transfer.d.ts +31 -21
- package/dist/components/components/transfer.js +49 -35
- package/dist/components/components/transfer.js.map +1 -1
- package/dist/components/project-list.js.map +1 -1
- package/dist/components/project-session.d.ts +6 -3
- package/dist/components/project-session.js +14 -8
- package/dist/components/project-session.js.map +1 -1
- package/dist/components/project-switcher.js.map +1 -1
- package/dist/components/rail-view-source.js +2 -1
- package/dist/components/rail-view-source.js.map +1 -1
- package/dist/components/section-nav.js +1 -1
- package/dist/components/section-nav.js.map +1 -1
- package/dist/lib/ai/apply-content.js +56 -116
- package/dist/lib/ai/apply-content.js.map +1 -1
- package/dist/lib/ai/chat-context.d.ts +8 -0
- package/dist/lib/ai/chat-context.js +37 -6
- package/dist/lib/ai/chat-context.js.map +1 -1
- package/dist/lib/ai/chat-state.d.ts +14 -1
- package/dist/lib/ai/chat-state.js.map +1 -1
- package/dist/lib/ai/constraints.d.ts +20 -5
- package/dist/lib/ai/constraints.js +125 -33
- package/dist/lib/ai/constraints.js.map +1 -1
- package/dist/lib/ai/fake-provider.d.ts +16 -3
- package/dist/lib/ai/fake-provider.js +22 -6
- package/dist/lib/ai/fake-provider.js.map +1 -1
- package/dist/lib/ai/index.d.ts +2 -0
- package/dist/lib/ai/index.js +2 -0
- package/dist/lib/ai/index.js.map +1 -1
- package/dist/lib/ai/leash.d.ts +34 -0
- package/dist/lib/ai/leash.js +28 -0
- package/dist/lib/ai/leash.js.map +1 -0
- package/dist/lib/ai/provenance.d.ts +1 -1
- package/dist/lib/ai/provenance.js.map +1 -1
- package/dist/lib/ai/rich-text-input.d.ts +8 -8
- package/dist/lib/ai/rich-text-input.js +2 -1
- package/dist/lib/ai/rich-text-input.js.map +1 -1
- package/dist/lib/ai/rich-text-translate.d.ts +27 -4
- package/dist/lib/ai/rich-text-translate.js +28 -10
- package/dist/lib/ai/rich-text-translate.js.map +1 -1
- package/dist/lib/ai/shape.d.ts +13 -13
- package/dist/lib/ai/shape.js +69 -93
- package/dist/lib/ai/shape.js.map +1 -1
- package/dist/lib/ai/tools.d.ts +36 -41
- package/dist/lib/ai/tools.js +85 -87
- package/dist/lib/ai/tools.js.map +1 -1
- package/dist/lib/ai/translate-document.d.ts +39 -5
- package/dist/lib/ai/translate-document.js +160 -51
- package/dist/lib/ai/translate-document.js.map +1 -1
- package/dist/lib/ai/types.d.ts +34 -23
- package/dist/lib/ai/types.js.map +1 -1
- package/dist/lib/ai/update-fields.d.ts +21 -12
- package/dist/lib/ai/update-fields.js +118 -177
- package/dist/lib/ai/update-fields.js.map +1 -1
- package/dist/lib/ai/writer-form.d.ts +116 -0
- package/dist/lib/ai/writer-form.js +429 -0
- package/dist/lib/ai/writer-form.js.map +1 -0
- package/dist/lib/ai-current-document.d.ts +11 -11
- package/dist/lib/ai-current-document.js +4 -4
- package/dist/lib/ai-current-document.js.map +1 -1
- package/dist/lib/assets/upload.d.ts +31 -2
- package/dist/lib/assets/upload.js +61 -6
- package/dist/lib/assets/upload.js.map +1 -1
- package/dist/lib/clipboard/os-clipboard.d.ts +10 -2
- package/dist/lib/clipboard/os-clipboard.js +8 -4
- package/dist/lib/clipboard/os-clipboard.js.map +1 -1
- package/dist/lib/clipboard/paste-target.d.ts +18 -9
- package/dist/lib/clipboard/paste-target.js +8 -7
- package/dist/lib/clipboard/paste-target.js.map +1 -1
- package/dist/lib/cms/field-patch.d.ts +15 -0
- package/dist/lib/cms/field-patch.js +25 -0
- package/dist/lib/cms/field-patch.js.map +1 -0
- package/dist/lib/cms/published-documents.d.ts +1 -1
- package/dist/lib/cms/published-documents.js +1 -1
- package/dist/lib/cms/published-documents.js.map +1 -1
- package/dist/lib/cms-views/view-model.d.ts +3 -3
- package/dist/lib/collection-view/__fixtures__/document-writes.d.ts +6 -0
- package/dist/lib/collection-view/__fixtures__/document-writes.js +23 -0
- package/dist/lib/collection-view/__fixtures__/document-writes.js.map +1 -0
- package/dist/lib/collection-view/collection-view-source.d.ts +69 -6
- package/dist/lib/collection-view/collection-view-source.js.map +1 -1
- package/dist/lib/data/collection-content.d.ts +4 -13
- package/dist/lib/data/collection-content.js +11 -5
- package/dist/lib/data/collection-content.js.map +1 -1
- package/dist/lib/dnd/drop-rules.d.ts +25 -31
- package/dist/lib/dnd/drop-rules.js +53 -59
- package/dist/lib/dnd/drop-rules.js.map +1 -1
- package/dist/lib/engine-version.d.ts +1 -1
- package/dist/lib/engine-version.js +1 -1
- package/dist/lib/engine-version.js.map +1 -1
- package/dist/lib/i18n/messages.de.js +72 -15
- package/dist/lib/i18n/messages.de.js.map +1 -1
- package/dist/lib/i18n/messages.en.d.ts +61 -12
- package/dist/lib/i18n/messages.en.js +76 -16
- package/dist/lib/i18n/messages.en.js.map +1 -1
- package/dist/lib/operations/__fixtures__/write-document.d.ts +30 -0
- package/dist/lib/operations/__fixtures__/write-document.js +16 -0
- package/dist/lib/operations/__fixtures__/write-document.js.map +1 -0
- package/dist/lib/operations/cms-persistence.d.ts +124 -31
- package/dist/lib/operations/cms-persistence.js +447 -68
- package/dist/lib/operations/cms-persistence.js.map +1 -1
- package/dist/lib/operations/config-manifest-lookup.d.ts +35 -0
- package/dist/lib/operations/config-manifest-lookup.js +56 -0
- package/dist/lib/operations/config-manifest-lookup.js.map +1 -0
- package/dist/lib/operations/project-runtime-config.d.ts +39 -0
- package/dist/lib/operations/project-runtime-config.js +54 -0
- package/dist/lib/operations/project-runtime-config.js.map +1 -0
- package/dist/lib/operations/publish-with-revision.d.ts +64 -0
- package/dist/lib/operations/publish-with-revision.js +66 -0
- package/dist/lib/operations/publish-with-revision.js.map +1 -0
- package/dist/lib/operations/runtime-validator.d.ts +32 -0
- package/dist/lib/operations/runtime-validator.js +18 -0
- package/dist/lib/operations/runtime-validator.js.map +1 -0
- package/dist/lib/operations/session-hydration.d.ts +31 -14
- package/dist/lib/operations/session-hydration.js +12 -16
- package/dist/lib/operations/session-hydration.js.map +1 -1
- package/dist/lib/operations/studio-operations.d.ts +59 -2
- package/dist/lib/operations/studio-operations.js +76 -14
- package/dist/lib/operations/studio-operations.js.map +1 -1
- package/dist/lib/persistence/convex-adapter.d.ts +13 -5
- package/dist/lib/persistence/convex-adapter.js +189 -74
- package/dist/lib/persistence/convex-adapter.js.map +1 -1
- package/dist/lib/persistence/convex-client.d.ts +65 -5
- package/dist/lib/persistence/convex-client.js +106 -3
- package/dist/lib/persistence/convex-client.js.map +1 -1
- package/dist/lib/persistence/index.js +17 -18
- package/dist/lib/persistence/index.js.map +1 -1
- package/dist/lib/persona/labels.js +4 -1
- package/dist/lib/persona/labels.js.map +1 -1
- package/dist/lib/query/operations-query.d.ts +1 -1
- package/dist/lib/query/operations-query.js +1 -1
- package/dist/lib/query/operations-query.js.map +1 -1
- package/dist/lib/references/impact.d.ts +21 -15
- package/dist/lib/references/impact.js +13 -26
- package/dist/lib/references/impact.js.map +1 -1
- package/dist/lib/references/references-store.d.ts +9 -0
- package/dist/lib/references/references-store.js +24 -4
- package/dist/lib/references/references-store.js.map +1 -1
- package/dist/lib/routes/route-issues.d.ts +6 -6
- package/dist/lib/routes/route-issues.js +26 -80
- package/dist/lib/routes/route-issues.js.map +1 -1
- package/dist/lib/workspace/config-issues.js +2 -1
- package/dist/lib/workspace/config-issues.js.map +1 -1
- package/dist/lib/workspace/index.d.ts +31 -1
- package/dist/lib/workspace/index.js +64 -17
- package/dist/lib/workspace/index.js.map +1 -1
- package/dist/lib/workspace/switcher-source.d.ts +3 -3
- package/dist/lib/workspace/switcher-source.js.map +1 -1
- package/dist/lib/workspace/workspace-source.d.ts +2 -2
- package/dist/lib/workspace/workspace-source.js +2 -1
- package/dist/lib/workspace/workspace-source.js.map +1 -1
- package/package.json +3 -3
- package/dist/components/cms/cms-composition-validators.d.ts +0 -16
- package/dist/components/cms/cms-composition-validators.js +0 -133
- package/dist/components/cms/cms-composition-validators.js.map +0 -1
- package/dist/components/cms/publish-clean.d.ts +0 -28
- package/dist/components/cms/publish-clean.js +0 -38
- package/dist/components/cms/publish-clean.js.map +0 -1
- package/dist/components/cms/use-save-mode.d.ts +0 -35
- package/dist/components/cms/use-save-mode.js +0 -54
- package/dist/components/cms/use-save-mode.js.map +0 -1
- package/dist/lib/assets/asset-placements.d.ts +0 -28
- package/dist/lib/assets/asset-placements.js +0 -83
- package/dist/lib/assets/asset-placements.js.map +0 -1
- package/dist/lib/cms/document-gate.d.ts +0 -47
- package/dist/lib/cms/document-gate.js +0 -61
- package/dist/lib/cms/document-gate.js.map +0 -1
package/dist/lib/ai/shape.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CollectionDef, JsonSchema } from '@elytracms/core/cms-core';
|
|
2
|
-
import type {
|
|
3
|
-
/** A relation field's resolved candidate set
|
|
2
|
+
import type { WriterLeash } from './types.js';
|
|
3
|
+
/** A top-level relation field's resolved candidate set (the enum the model chose from). */
|
|
4
4
|
export interface TargetRelationField {
|
|
5
5
|
fieldName: string;
|
|
6
6
|
/** The relation's target collection id. */
|
|
@@ -9,7 +9,7 @@ export interface TargetRelationField {
|
|
|
9
9
|
/** The allowed candidate ids (the enum the model chose from). */
|
|
10
10
|
candidateIds: string[];
|
|
11
11
|
}
|
|
12
|
-
/**
|
|
12
|
+
/** A top-level asset field's resolved candidate set (EC-381). */
|
|
13
13
|
export interface TargetAssetField {
|
|
14
14
|
fieldName: string;
|
|
15
15
|
multiple: boolean;
|
|
@@ -22,26 +22,26 @@ export interface TargetShape {
|
|
|
22
22
|
schema: JsonSchema;
|
|
23
23
|
/** Field names removed by `ai.exclude` (untouchable). */
|
|
24
24
|
excluded: string[];
|
|
25
|
+
/** Field names omitted because a writer never writes them — a composition (4c). */
|
|
26
|
+
compositions: string[];
|
|
25
27
|
/** Field names whose values route under `localized[locale]`. */
|
|
26
28
|
localizedFields: string[];
|
|
27
|
-
/**
|
|
29
|
+
/** Top-level relation fields with their candidate enums. */
|
|
28
30
|
relationFields: TargetRelationField[];
|
|
29
|
-
/**
|
|
31
|
+
/** Top-level asset fields with their candidate enums (EC-381). */
|
|
30
32
|
assetFields: TargetAssetField[];
|
|
31
33
|
}
|
|
32
34
|
export interface BuildTargetShapeInput {
|
|
33
35
|
collection: CollectionDef;
|
|
34
|
-
/**
|
|
35
|
-
|
|
36
|
-
/** Asset candidate ids by field — an asset field with none is omitted from the shape (EC-381). */
|
|
37
|
-
assetCandidates?: AssetCandidates;
|
|
36
|
+
/** What the model searched — the id leash at every position (absent → nothing searched). */
|
|
37
|
+
leash?: WriterLeash;
|
|
38
38
|
/** UI locale for resolving field labels into descriptions. */
|
|
39
39
|
locale?: string;
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
42
|
-
* Build the leash-aware target shape from a collection +
|
|
43
|
-
* never throws. Reuses `collectionJsonSchema` as the base (its
|
|
44
|
-
* gives every property its writer form (EC-556)
|
|
45
|
-
* excluded fields.
|
|
42
|
+
* Build the leash-aware target shape from a collection + what the model searched.
|
|
43
|
+
* Deterministic; never throws. Reuses `collectionJsonSchema` as the base (its
|
|
44
|
+
* `required` list), then gives every property its writer form (EC-556) — id enums at
|
|
45
|
+
* every depth (EC-593) — and strips excluded fields and compositions.
|
|
46
46
|
*/
|
|
47
47
|
export declare function buildTargetShape(input: BuildTargetShapeInput): TargetShape;
|
package/dist/lib/ai/shape.js
CHANGED
|
@@ -2,24 +2,28 @@
|
|
|
2
2
|
* Target-shape derivation for `applyContentWithShape` (EC-331).
|
|
3
3
|
*
|
|
4
4
|
* Reuses the existing collection→JSON-Schema derivation (`collectionJsonSchema`,
|
|
5
|
-
* cms-core) rather than writing a new one, then applies the
|
|
6
|
-
*
|
|
5
|
+
* cms-core) rather than writing a new one, then applies the leashes the AI engine
|
|
6
|
+
* adds on top:
|
|
7
7
|
*
|
|
8
8
|
* - `ai.exclude` fields are removed entirely (the model never sees them → cannot
|
|
9
9
|
* write them).
|
|
10
|
-
* - relation
|
|
11
|
-
* when
|
|
12
|
-
* as valid structured output.
|
|
13
|
-
* - asset
|
|
14
|
-
* omitted when none
|
|
15
|
-
* proposed asset id must be a real, `listAssets`-returned
|
|
16
|
-
*
|
|
17
|
-
*
|
|
10
|
+
* - relation ids become an ENUM over the searched candidates of the relation's
|
|
11
|
+
* target (or the position is omitted when none were searched) — so a hallucinated
|
|
12
|
+
* relation id is not representable as valid structured output.
|
|
13
|
+
* - asset ids become an ENUM over the searched library assets that fit the
|
|
14
|
+
* position's `accept` (or the position is omitted when none fit) — EC-381, the SAME
|
|
15
|
+
* leash as relations: a proposed asset id must be a real, `listAssets`-returned
|
|
16
|
+
* library asset (empty beats wrong; the assistant never generates or uploads).
|
|
17
|
+
* EC-593: both leashes hold at EVERY depth — a relation in an object, an asset in a
|
|
18
|
+
* repeater item — not only on a top-level field (`writerFieldSchema(field, leash)`).
|
|
18
19
|
* - rich-text fields are MARKDOWN STRINGS (EC-379): the description names the
|
|
19
|
-
* allowed subset, and the engine converts md → the `{ version,
|
|
20
|
-
*
|
|
21
|
-
* EMBEDS only — markdown cannot express an embed, so the leash is
|
|
22
|
-
* construction (and still enforced downstream by `validateRichTextEmbeds`).
|
|
20
|
+
* allowed subset, and the engine converts md → the `{ version: 2, content }` storage
|
|
21
|
+
* value at proposal-build time (`writer-form.ts`). The field's `allow` config leashes
|
|
22
|
+
* component EMBEDS only — markdown cannot express an embed, so the leash is
|
|
23
|
+
* satisfied by construction (and still enforced downstream by `validateRichTextEmbeds`).
|
|
24
|
+
* - a composition (`blocks`) has NO writer form (ratified 4c, EC-593): it is omitted,
|
|
25
|
+
* and the schema's own description says so — the omission is visible, never a field
|
|
26
|
+
* the model simply never hears of.
|
|
23
27
|
*
|
|
24
28
|
* Localized fields stay flat in the shape (the model authors one locale at a time);
|
|
25
29
|
* the engine routes their values under `localized[locale]`.
|
|
@@ -46,12 +50,12 @@
|
|
|
46
50
|
* EC-556 — the projection is VALIDATOR-facing (the value at rest: asset/relation
|
|
47
51
|
* envelopes, the v2 rich-text object). Every property here is its WRITER form
|
|
48
52
|
* (`writerFieldSchema`), derived from that projection at every depth — a bare asset
|
|
49
|
-
* id, a
|
|
50
|
-
*
|
|
51
|
-
* top-level relation/asset id enums (EC-381) override the writer form there.
|
|
53
|
+
* id, a relation id, a markdown string — so an asset, relation or rich-text SUBFIELD of
|
|
54
|
+
* an `object` is told the same form as a top-level one.
|
|
52
55
|
*/
|
|
53
56
|
import { collectionJsonSchema, resolveLabel } from '@elytracms/core/cms-core';
|
|
54
57
|
import { constraintSentence, toModelFacingSchema, writerFieldSchema } from './constraints.js';
|
|
58
|
+
import { NO_SEARCHED_IDS } from './leash.js';
|
|
55
59
|
/**
|
|
56
60
|
* A field's model-facing description: resolved label + optional `ai.hint` + the
|
|
57
61
|
* constraint clause (EC-473). The constraints are stated in PROSE because that is
|
|
@@ -66,17 +70,19 @@ function describe(field, locale) {
|
|
|
66
70
|
return parts.length > 0 ? parts.join(' — ') : undefined;
|
|
67
71
|
}
|
|
68
72
|
/**
|
|
69
|
-
* Build the leash-aware target shape from a collection +
|
|
70
|
-
* never throws. Reuses `collectionJsonSchema` as the base (its
|
|
71
|
-
* gives every property its writer form (EC-556)
|
|
72
|
-
* excluded fields.
|
|
73
|
+
* Build the leash-aware target shape from a collection + what the model searched.
|
|
74
|
+
* Deterministic; never throws. Reuses `collectionJsonSchema` as the base (its
|
|
75
|
+
* `required` list), then gives every property its writer form (EC-556) — id enums at
|
|
76
|
+
* every depth (EC-593) — and strips excluded fields and compositions.
|
|
73
77
|
*/
|
|
74
78
|
export function buildTargetShape(input) {
|
|
79
|
+
const leash = input.leash ?? NO_SEARCHED_IDS;
|
|
75
80
|
const base = collectionJsonSchema(input.collection);
|
|
76
81
|
const properties = {
|
|
77
82
|
...(base.properties ?? {}),
|
|
78
83
|
};
|
|
79
84
|
const excluded = [];
|
|
85
|
+
const compositions = [];
|
|
80
86
|
const localizedFields = [];
|
|
81
87
|
const relationFields = [];
|
|
82
88
|
const assetFields = [];
|
|
@@ -88,82 +94,46 @@ export function buildTargetShape(input) {
|
|
|
88
94
|
delete properties[field.name];
|
|
89
95
|
continue;
|
|
90
96
|
}
|
|
97
|
+
// EC-556: the writer form at every depth (rich text → markdown, EC-379 / D2;
|
|
98
|
+
// nested asset / relation → the bare forms the write-time lens wraps); EC-593:
|
|
99
|
+
// every id an enum over what was searched for that position.
|
|
100
|
+
const written = writerFieldSchema(field, leash);
|
|
101
|
+
if (written === undefined) {
|
|
102
|
+
// No writer form: a composition (4c), or a relation / asset with nothing
|
|
103
|
+
// searched for it — the model cannot emit a value, so a hallucinated id is
|
|
104
|
+
// structurally impossible (empty beats wrong).
|
|
105
|
+
if (field.type === 'blocks')
|
|
106
|
+
compositions.push(field.name);
|
|
107
|
+
delete properties[field.name];
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
91
110
|
if (field.type === 'relation') {
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
// No candidate ids ⇒ omit the field: the model cannot emit a relation value
|
|
95
|
-
// at all, so a hallucinated id is structurally impossible.
|
|
96
|
-
delete properties[field.name];
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
const ids = candidates.map((c) => c.id);
|
|
100
|
-
const label = candidates
|
|
101
|
-
.map((c) => (c.label ? `${c.id} (${c.label})` : c.id))
|
|
102
|
-
.join(', ');
|
|
103
|
-
const idSchema = {
|
|
104
|
-
type: 'string',
|
|
105
|
-
enum: ids,
|
|
106
|
-
description: `Choose one of: ${label}`,
|
|
107
|
-
};
|
|
108
|
-
properties[field.name] = field.multiple ? { type: 'array', items: idSchema } : idSchema;
|
|
109
|
-
relationFields.push({
|
|
110
|
-
fieldName: field.name,
|
|
111
|
-
target: field.target,
|
|
112
|
-
multiple: field.multiple,
|
|
113
|
-
candidateIds: ids,
|
|
114
|
-
});
|
|
111
|
+
const candidateIds = leash.relationCandidates(field.target).map((c) => c.id);
|
|
112
|
+
relationFields.push({ fieldName: field.name, target: field.target, multiple: field.multiple, candidateIds });
|
|
115
113
|
}
|
|
116
114
|
else if (field.type === 'asset') {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
// searched assets ⇒ omit the field, so the proposal simply leaves it empty
|
|
120
|
-
// (an invented / to-be-uploaded id is structurally unrepresentable).
|
|
121
|
-
const candidates = input.assetCandidates?.[field.name] ?? [];
|
|
122
|
-
if (candidates.length === 0) {
|
|
123
|
-
delete properties[field.name];
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
const ids = candidates.map((c) => c.id);
|
|
127
|
-
const label = candidates
|
|
128
|
-
.map((c) => (c.label ? `${c.id} (${c.label})` : c.id))
|
|
129
|
-
.join(', ');
|
|
130
|
-
const idSchema = {
|
|
131
|
-
type: 'string',
|
|
132
|
-
enum: ids,
|
|
133
|
-
description: `Choose an EXISTING library asset id, one of: ${label}. Leave empty if none fits.`,
|
|
134
|
-
};
|
|
135
|
-
properties[field.name] = field.multiple ? { type: 'array', items: idSchema } : idSchema;
|
|
136
|
-
assetFields.push({ fieldName: field.name, multiple: field.multiple, candidateIds: ids });
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
// EC-556: the writer form at every depth (rich text → markdown, EC-379 / D2;
|
|
140
|
-
// nested asset / relation → the bare forms the write-time lens wraps).
|
|
141
|
-
properties[field.name] = writerFieldSchema(field);
|
|
115
|
+
const candidateIds = leash.assetCandidates(field).map((c) => c.id);
|
|
116
|
+
assetFields.push({ fieldName: field.name, multiple: field.multiple, candidateIds });
|
|
142
117
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
? desc
|
|
161
|
-
: constraints !== undefined
|
|
162
|
-
? `${existing} — ${constraints}`
|
|
163
|
-
: existing;
|
|
164
|
-
}
|
|
165
|
-
properties[field.name] = next;
|
|
118
|
+
// EC-473: a `pattern` next to a `format` is 200+ characters that teach the
|
|
119
|
+
// model nothing — the format (and the prose constraints below) say it better.
|
|
120
|
+
const stripped = toModelFacingSchema(written);
|
|
121
|
+
const desc = describe(field, input.locale);
|
|
122
|
+
// Preserve an existing description (e.g. relation enum / rich-text note), but
|
|
123
|
+
// append the constraint clause to it — the enum leash and the value rules are
|
|
124
|
+
// different facts and the model needs both.
|
|
125
|
+
const next = stripped === written ? { ...written } : { ...stripped };
|
|
126
|
+
if (desc !== undefined) {
|
|
127
|
+
const existing = typeof next.description === 'string' ? next.description : undefined;
|
|
128
|
+
const constraints = constraintSentence(field);
|
|
129
|
+
next.description =
|
|
130
|
+
existing === undefined
|
|
131
|
+
? desc
|
|
132
|
+
: constraints !== undefined
|
|
133
|
+
? `${existing} — ${constraints}`
|
|
134
|
+
: existing;
|
|
166
135
|
}
|
|
136
|
+
properties[field.name] = next;
|
|
167
137
|
}
|
|
168
138
|
const requiredIn = Array.isArray(base.required) ? base.required : [];
|
|
169
139
|
const required = requiredIn.filter((n) => !excluded.includes(n) && properties[n] !== undefined);
|
|
@@ -172,7 +142,13 @@ export function buildTargetShape(input) {
|
|
|
172
142
|
properties,
|
|
173
143
|
additionalProperties: false,
|
|
174
144
|
...(required.length > 0 ? { required } : {}),
|
|
145
|
+
// 4c (EC-593): the omission is said, not silent.
|
|
146
|
+
...(compositions.length > 0
|
|
147
|
+
? {
|
|
148
|
+
description: `Not part of this object: ${compositions.join(', ')} — page-builder composition${compositions.length > 1 ? 's' : ''} whose components are added, moved and removed on the canvas, never by the assistant.`,
|
|
149
|
+
}
|
|
150
|
+
: {}),
|
|
175
151
|
};
|
|
176
|
-
return { schema, excluded, localizedFields, relationFields, assetFields };
|
|
152
|
+
return { schema, excluded, compositions, localizedFields, relationFields, assetFields };
|
|
177
153
|
}
|
|
178
154
|
//# sourceMappingURL=shape.js.map
|
package/dist/lib/ai/shape.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shape.js","sourceRoot":"","sources":["../../../src/lib/ai/shape.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Target-shape derivation for `applyContentWithShape` (EC-331).\n *\n * Reuses the existing collection→JSON-Schema derivation (`collectionJsonSchema`,\n * cms-core) rather than writing a new one, then applies the three leashes the AI\n * engine adds on top:\n *\n * - `ai.exclude` fields are removed entirely (the model never sees them → cannot\n * write them).\n * - relation fields become an ENUM over the provided candidate ids (or are omitted\n * when no candidates exist) — so a hallucinated relation id is not representable\n * as valid structured output.\n * - asset/image fields become an ENUM over the searched library asset ids (or are\n * omitted when none were searched) — EC-381, the SAME leash as relations: a\n * proposed asset id must be a real, `listAssets`-returned library asset, and a\n * create shape with no searched assets simply has no asset property (empty beats\n * wrong; the assistant never generates or uploads).\n * - rich-text fields are MARKDOWN STRINGS (EC-379): the description names the\n * allowed subset, and the engine converts md → the `{ version, doc }` storage\n * envelope at proposal-build time. The field's `allow` config leashes component\n * EMBEDS only — markdown cannot express an embed, so the leash is satisfied by\n * construction (and still enforced downstream by `validateRichTextEmbeds`).\n *\n * Localized fields stay flat in the shape (the model authors one locale at a time);\n * the engine routes their values under `localized[locale]`.\n *\n * EC-473 — the shape now consumes the ONE constraint projection, so a rule declared\n * in config actually reaches the model:\n *\n * - `collectionJsonSchema` merges declarative rules with the fragment derived from\n * a schema-form `validation.validate`, so `{ min: 2 }` and `z.string().min(2)`\n * arrive identically (and a declared DATE RANGE arrives at all — it previously\n * reached no consumer whatsoever);\n * - a rich-text field no longer OVERWRITES its constraints: the markdown schema is\n * merged over them instead of replacing them (measured drift, EC-474 §2);\n * - a `pattern` is dropped wherever a `format` explains the same thing (a\n * 200-character email regex teaches a model nothing and costs real tokens);\n * - a field whose projection is knowingly partial (`schemaComplete: false`) SAYS SO\n * in its description rather than presenting the partial rule as the whole rule.\n *\n * EC-505 — one further narrowing of what the model is TOLD (never of what the engine\n * accepts): a `date` property is `type: 'string'` + `format: 'date-time'` rather than\n * the `['string','number']` union the general projection carries, because the model is\n * asked to author an ISO instant (EC-472) and some providers reject a union `type`.\n *\n * EC-556 — the projection is VALIDATOR-facing (the value at rest: asset/relation\n * envelopes, the v2 rich-text object). Every property here is its WRITER form\n * (`writerFieldSchema`), derived from that projection at every depth — a bare asset\n * id, a `{ collection, id }` reference, a markdown string — so an asset, relation or\n * rich-text SUBFIELD of an `object` is told the same form as a top-level one. The\n * top-level relation/asset id enums (EC-381) override the writer form there.\n */\nimport { collectionJsonSchema, resolveLabel } from '@elytracms/core/cms-core'\nimport type { CollectionDef, FieldDef, JsonSchema } from '@elytracms/core/cms-core'\nimport { constraintSentence, toModelFacingSchema, writerFieldSchema } from './constraints'\nimport type { AssetCandidates, RelationCandidates } from './types'\n\n/** A relation field's resolved candidate set — how the engine maps ids → reference envelopes. */\nexport interface TargetRelationField {\n fieldName: string\n /** The relation's target collection id. */\n target: string\n multiple: boolean\n /** The allowed candidate ids (the enum the model chose from). */\n candidateIds: string[]\n}\n\n/** An asset field's resolved candidate set — how the engine maps ids → asset envelopes (EC-381). */\nexport interface TargetAssetField {\n fieldName: string\n multiple: boolean\n /** The allowed library asset ids (the enum the model chose from). */\n candidateIds: string[]\n}\n\n/** The derived target shape + the metadata the engine needs to post-process the output. */\nexport interface TargetShape {\n /** The JSON Schema the structured output must satisfy. */\n schema: JsonSchema\n /** Field names removed by `ai.exclude` (untouchable). */\n excluded: string[]\n /** Field names whose values route under `localized[locale]`. */\n localizedFields: string[]\n /** Relation fields with their candidate enums. */\n relationFields: TargetRelationField[]\n /** Asset fields with their candidate enums (EC-381). */\n assetFields: TargetAssetField[]\n}\n\nexport interface BuildTargetShapeInput {\n collection: CollectionDef\n /** Relation candidate ids by field — a relation field with none is omitted from the shape. */\n candidates?: RelationCandidates\n /** Asset candidate ids by field — an asset field with none is omitted from the shape (EC-381). */\n assetCandidates?: AssetCandidates\n /** UI locale for resolving field labels into descriptions. */\n locale?: string\n}\n\n/**\n * A field's model-facing description: resolved label + optional `ai.hint` + the\n * constraint clause (EC-473). The constraints are stated in PROSE because that is\n * what a model acts on — the same facts also ride as JSON-Schema keywords for the\n * structured-output validator, which is a different reader.\n */\nfunction describe(field: FieldDef, locale?: string): string | undefined {\n const label = resolveLabel(field.form?.label, locale) ?? field.name\n const hint = field.ai?.hint\n const constraints = constraintSentence(field)\n const parts = [label, hint, constraints].filter(\n (p): p is string => typeof p === 'string' && p.length > 0,\n )\n return parts.length > 0 ? parts.join(' — ') : undefined\n}\n\n/**\n * Build the leash-aware target shape from a collection + candidates. Deterministic;\n * never throws. Reuses `collectionJsonSchema` as the base (its `required` list), then\n * gives every property its writer form (EC-556) or its id-enum leash, and strips\n * excluded fields.\n */\nexport function buildTargetShape(input: BuildTargetShapeInput): TargetShape {\n const base = collectionJsonSchema(input.collection)\n const properties: Record<string, JsonSchema> = {\n ...((base.properties as Record<string, JsonSchema>) ?? {}),\n }\n const excluded: string[] = []\n const localizedFields: string[] = []\n const relationFields: TargetRelationField[] = []\n const assetFields: TargetAssetField[] = []\n\n for (const field of input.collection.fields) {\n if (field.localized) localizedFields.push(field.name)\n\n if (field.ai?.exclude) {\n excluded.push(field.name)\n delete properties[field.name]\n continue\n }\n\n if (field.type === 'relation') {\n const candidates = input.candidates?.[field.name] ?? []\n if (candidates.length === 0) {\n // No candidate ids ⇒ omit the field: the model cannot emit a relation value\n // at all, so a hallucinated id is structurally impossible.\n delete properties[field.name]\n continue\n }\n const ids = candidates.map((c) => c.id)\n const label = candidates\n .map((c) => (c.label ? `${c.id} (${c.label})` : c.id))\n .join(', ')\n const idSchema: JsonSchema = {\n type: 'string',\n enum: ids,\n description: `Choose one of: ${label}`,\n }\n properties[field.name] = field.multiple ? { type: 'array', items: idSchema } : idSchema\n relationFields.push({\n fieldName: field.name,\n target: field.target,\n multiple: field.multiple,\n candidateIds: ids,\n })\n } else if (field.type === 'asset') {\n // EC-381 — same leash as relations: an asset field is an enum over the ids\n // the model actually searched in the media library (`listAssets`). No\n // searched assets ⇒ omit the field, so the proposal simply leaves it empty\n // (an invented / to-be-uploaded id is structurally unrepresentable).\n const candidates = input.assetCandidates?.[field.name] ?? []\n if (candidates.length === 0) {\n delete properties[field.name]\n continue\n }\n const ids = candidates.map((c) => c.id)\n const label = candidates\n .map((c) => (c.label ? `${c.id} (${c.label})` : c.id))\n .join(', ')\n const idSchema: JsonSchema = {\n type: 'string',\n enum: ids,\n description: `Choose an EXISTING library asset id, one of: ${label}. Leave empty if none fits.`,\n }\n properties[field.name] = field.multiple ? { type: 'array', items: idSchema } : idSchema\n assetFields.push({ fieldName: field.name, multiple: field.multiple, candidateIds: ids })\n } else {\n // EC-556: the writer form at every depth (rich text → markdown, EC-379 / D2;\n // nested asset / relation → the bare forms the write-time lens wraps).\n properties[field.name] = writerFieldSchema(field)\n }\n\n const prop = properties[field.name]\n if (prop) {\n // EC-473: a `pattern` next to a `format` is 200+ characters that teach the\n // model nothing — the format (and the prose constraints below) say it better.\n // EC-505: and a `date`'s `['string','number']` union becomes the ISO string\n // the model is actually asked to author.\n const stripped = toModelFacingSchema(prop)\n const desc = describe(field, input.locale)\n // Preserve an existing description (e.g. relation enum / rich-text note), but\n // append the constraint clause to it — the enum leash and the value rules are\n // different facts and the model needs both.\n const next: JsonSchema = stripped === prop ? prop : { ...stripped }\n if (desc !== undefined) {\n const existing = typeof next.description === 'string' ? next.description : undefined\n const constraints = constraintSentence(field)\n next.description =\n existing === undefined\n ? desc\n : constraints !== undefined\n ? `${existing} — ${constraints}`\n : existing\n }\n properties[field.name] = next\n }\n }\n\n const requiredIn = Array.isArray(base.required) ? (base.required as string[]) : []\n const required = requiredIn.filter((n) => !excluded.includes(n) && properties[n] !== undefined)\n\n const schema: JsonSchema = {\n type: 'object',\n properties,\n additionalProperties: false,\n ...(required.length > 0 ? { required } : {}),\n }\n return { schema, excluded, localizedFields, relationFields, assetFields }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"shape.js","sourceRoot":"","sources":["../../../src/lib/ai/shape.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Target-shape derivation for `applyContentWithShape` (EC-331).\n *\n * Reuses the existing collection→JSON-Schema derivation (`collectionJsonSchema`,\n * cms-core) rather than writing a new one, then applies the leashes the AI engine\n * adds on top:\n *\n * - `ai.exclude` fields are removed entirely (the model never sees them → cannot\n * write them).\n * - relation ids become an ENUM over the searched candidates of the relation's\n * target (or the position is omitted when none were searched) — so a hallucinated\n * relation id is not representable as valid structured output.\n * - asset ids become an ENUM over the searched library assets that fit the\n * position's `accept` (or the position is omitted when none fit) — EC-381, the SAME\n * leash as relations: a proposed asset id must be a real, `listAssets`-returned\n * library asset (empty beats wrong; the assistant never generates or uploads).\n * EC-593: both leashes hold at EVERY depth — a relation in an object, an asset in a\n * repeater item — not only on a top-level field (`writerFieldSchema(field, leash)`).\n * - rich-text fields are MARKDOWN STRINGS (EC-379): the description names the\n * allowed subset, and the engine converts md → the `{ version: 2, content }` storage\n * value at proposal-build time (`writer-form.ts`). The field's `allow` config leashes\n * component EMBEDS only — markdown cannot express an embed, so the leash is\n * satisfied by construction (and still enforced downstream by `validateRichTextEmbeds`).\n * - a composition (`blocks`) has NO writer form (ratified 4c, EC-593): it is omitted,\n * and the schema's own description says so — the omission is visible, never a field\n * the model simply never hears of.\n *\n * Localized fields stay flat in the shape (the model authors one locale at a time);\n * the engine routes their values under `localized[locale]`.\n *\n * EC-473 — the shape now consumes the ONE constraint projection, so a rule declared\n * in config actually reaches the model:\n *\n * - `collectionJsonSchema` merges declarative rules with the fragment derived from\n * a schema-form `validation.validate`, so `{ min: 2 }` and `z.string().min(2)`\n * arrive identically (and a declared DATE RANGE arrives at all — it previously\n * reached no consumer whatsoever);\n * - a rich-text field no longer OVERWRITES its constraints: the markdown schema is\n * merged over them instead of replacing them (measured drift, EC-474 §2);\n * - a `pattern` is dropped wherever a `format` explains the same thing (a\n * 200-character email regex teaches a model nothing and costs real tokens);\n * - a field whose projection is knowingly partial (`schemaComplete: false`) SAYS SO\n * in its description rather than presenting the partial rule as the whole rule.\n *\n * EC-505 — one further narrowing of what the model is TOLD (never of what the engine\n * accepts): a `date` property is `type: 'string'` + `format: 'date-time'` rather than\n * the `['string','number']` union the general projection carries, because the model is\n * asked to author an ISO instant (EC-472) and some providers reject a union `type`.\n *\n * EC-556 — the projection is VALIDATOR-facing (the value at rest: asset/relation\n * envelopes, the v2 rich-text object). Every property here is its WRITER form\n * (`writerFieldSchema`), derived from that projection at every depth — a bare asset\n * id, a relation id, a markdown string — so an asset, relation or rich-text SUBFIELD of\n * an `object` is told the same form as a top-level one.\n */\nimport { collectionJsonSchema, resolveLabel } from '@elytracms/core/cms-core'\nimport type { CollectionDef, FieldDef, JsonSchema } from '@elytracms/core/cms-core'\nimport { constraintSentence, toModelFacingSchema, writerFieldSchema } from './constraints'\nimport { NO_SEARCHED_IDS } from './leash'\nimport type { WriterLeash } from './types'\n\n/** A top-level relation field's resolved candidate set (the enum the model chose from). */\nexport interface TargetRelationField {\n fieldName: string\n /** The relation's target collection id. */\n target: string\n multiple: boolean\n /** The allowed candidate ids (the enum the model chose from). */\n candidateIds: string[]\n}\n\n/** A top-level asset field's resolved candidate set (EC-381). */\nexport interface TargetAssetField {\n fieldName: string\n multiple: boolean\n /** The allowed library asset ids (the enum the model chose from). */\n candidateIds: string[]\n}\n\n/** The derived target shape + the metadata the engine needs to post-process the output. */\nexport interface TargetShape {\n /** The JSON Schema the structured output must satisfy. */\n schema: JsonSchema\n /** Field names removed by `ai.exclude` (untouchable). */\n excluded: string[]\n /** Field names omitted because a writer never writes them — a composition (4c). */\n compositions: string[]\n /** Field names whose values route under `localized[locale]`. */\n localizedFields: string[]\n /** Top-level relation fields with their candidate enums. */\n relationFields: TargetRelationField[]\n /** Top-level asset fields with their candidate enums (EC-381). */\n assetFields: TargetAssetField[]\n}\n\nexport interface BuildTargetShapeInput {\n collection: CollectionDef\n /** What the model searched — the id leash at every position (absent → nothing searched). */\n leash?: WriterLeash\n /** UI locale for resolving field labels into descriptions. */\n locale?: string\n}\n\n/**\n * A field's model-facing description: resolved label + optional `ai.hint` + the\n * constraint clause (EC-473). The constraints are stated in PROSE because that is\n * what a model acts on — the same facts also ride as JSON-Schema keywords for the\n * structured-output validator, which is a different reader.\n */\nfunction describe(field: FieldDef, locale?: string): string | undefined {\n const label = resolveLabel(field.form?.label, locale) ?? field.name\n const hint = field.ai?.hint\n const constraints = constraintSentence(field)\n const parts = [label, hint, constraints].filter(\n (p): p is string => typeof p === 'string' && p.length > 0,\n )\n return parts.length > 0 ? parts.join(' — ') : undefined\n}\n\n/**\n * Build the leash-aware target shape from a collection + what the model searched.\n * Deterministic; never throws. Reuses `collectionJsonSchema` as the base (its\n * `required` list), then gives every property its writer form (EC-556) — id enums at\n * every depth (EC-593) — and strips excluded fields and compositions.\n */\nexport function buildTargetShape(input: BuildTargetShapeInput): TargetShape {\n const leash = input.leash ?? NO_SEARCHED_IDS\n const base = collectionJsonSchema(input.collection)\n const properties: Record<string, JsonSchema> = {\n ...((base.properties as Record<string, JsonSchema>) ?? {}),\n }\n const excluded: string[] = []\n const compositions: string[] = []\n const localizedFields: string[] = []\n const relationFields: TargetRelationField[] = []\n const assetFields: TargetAssetField[] = []\n\n for (const field of input.collection.fields) {\n if (field.localized) localizedFields.push(field.name)\n\n if (field.ai?.exclude) {\n excluded.push(field.name)\n delete properties[field.name]\n continue\n }\n\n // EC-556: the writer form at every depth (rich text → markdown, EC-379 / D2;\n // nested asset / relation → the bare forms the write-time lens wraps); EC-593:\n // every id an enum over what was searched for that position.\n const written = writerFieldSchema(field, leash)\n if (written === undefined) {\n // No writer form: a composition (4c), or a relation / asset with nothing\n // searched for it — the model cannot emit a value, so a hallucinated id is\n // structurally impossible (empty beats wrong).\n if (field.type === 'blocks') compositions.push(field.name)\n delete properties[field.name]\n continue\n }\n if (field.type === 'relation') {\n const candidateIds = leash.relationCandidates(field.target).map((c) => c.id)\n relationFields.push({ fieldName: field.name, target: field.target, multiple: field.multiple, candidateIds })\n } else if (field.type === 'asset') {\n const candidateIds = leash.assetCandidates(field).map((c) => c.id)\n assetFields.push({ fieldName: field.name, multiple: field.multiple, candidateIds })\n }\n\n // EC-473: a `pattern` next to a `format` is 200+ characters that teach the\n // model nothing — the format (and the prose constraints below) say it better.\n const stripped = toModelFacingSchema(written)\n const desc = describe(field, input.locale)\n // Preserve an existing description (e.g. relation enum / rich-text note), but\n // append the constraint clause to it — the enum leash and the value rules are\n // different facts and the model needs both.\n const next: JsonSchema = stripped === written ? { ...written } : { ...stripped }\n if (desc !== undefined) {\n const existing = typeof next.description === 'string' ? next.description : undefined\n const constraints = constraintSentence(field)\n next.description =\n existing === undefined\n ? desc\n : constraints !== undefined\n ? `${existing} — ${constraints}`\n : existing\n }\n properties[field.name] = next\n }\n\n const requiredIn = Array.isArray(base.required) ? (base.required as string[]) : []\n const required = requiredIn.filter((n) => !excluded.includes(n) && properties[n] !== undefined)\n\n const schema: JsonSchema = {\n type: 'object',\n properties,\n additionalProperties: false,\n ...(required.length > 0 ? { required } : {}),\n // 4c (EC-593): the omission is said, not silent.\n ...(compositions.length > 0\n ? {\n description: `Not part of this object: ${compositions.join(', ')} — page-builder composition${compositions.length > 1 ? 's' : ''} whose components are added, moved and removed on the canvas, never by the assistant.`,\n }\n : {}),\n }\n return { schema, excluded, compositions, localizedFields, relationFields, assetFields }\n}\n"]}
|
package/dist/lib/ai/tools.d.ts
CHANGED
|
@@ -33,25 +33,18 @@
|
|
|
33
33
|
*/
|
|
34
34
|
import { z } from 'zod';
|
|
35
35
|
import type { CmsDocument, CollectionDef, CollectionRegistry, LocaleConfig, ValidateDocumentOptions } from '@elytracms/core/cms-core';
|
|
36
|
-
import type {
|
|
36
|
+
import type { SearchedAsset, SearchedDocument } from './leash.js';
|
|
37
|
+
import type { TranslateSkip } from './translate-document.js';
|
|
37
38
|
import type { ChatProposal } from './chat-state.js';
|
|
38
|
-
import type { AiProvider,
|
|
39
|
+
import type { AiProvider, ResolvedKnowledge, WriterLeash } from './types.js';
|
|
39
40
|
/** A document the model may reference as a relation target (from a `searchDocuments` read). */
|
|
40
|
-
export
|
|
41
|
-
id: string;
|
|
42
|
-
title?: string;
|
|
43
|
-
}
|
|
41
|
+
export type DocumentSearchResult = SearchedDocument;
|
|
44
42
|
/**
|
|
45
43
|
* An asset the model may reference (from a `listAssets` read). EC-588: it carries the
|
|
46
|
-
* two facts a field's `accept` is judged on, so each asset
|
|
47
|
-
* filtered to what that
|
|
44
|
+
* two facts a field's `accept` is judged on, so each asset position's candidates can be
|
|
45
|
+
* filtered to what that position takes — and the model can see what each asset is.
|
|
48
46
|
*/
|
|
49
|
-
export
|
|
50
|
-
id: string;
|
|
51
|
-
title?: string;
|
|
52
|
-
contentType: string;
|
|
53
|
-
filename: string;
|
|
54
|
-
}
|
|
47
|
+
export type AssetSearchResult = SearchedAsset;
|
|
55
48
|
/**
|
|
56
49
|
* The client-side, operations-backed readers the executor calls. The studio binds
|
|
57
50
|
* these to the user's authenticated operations client; tests bind an in-memory fake.
|
|
@@ -201,26 +194,18 @@ export type ChatToolOutcome = {
|
|
|
201
194
|
};
|
|
202
195
|
/**
|
|
203
196
|
* The per-conversation candidate store: every `searchDocuments` result is recorded
|
|
204
|
-
* per
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
197
|
+
* per collection, every `listAssets` result into one flat library pool (EC-381), and
|
|
198
|
+
* the terminal tools may only reference the ids gathered here. The store IS the
|
|
199
|
+
* {@link WriterLeash} the engines ask per position (EC-593): a relation by its target
|
|
200
|
+
* collection, an asset by its declaration's `accept` (EC-588) — so a nested relation, a
|
|
201
|
+
* component's asset prop and a top-level field are leashed by the same two questions
|
|
202
|
+
* (the create enum + drop, the update loud refusal). Held by the panel per
|
|
203
|
+
* conversation — a new conversation (EC-380 clear) starts an empty store.
|
|
210
204
|
*/
|
|
211
|
-
export interface ChatCandidateStore {
|
|
205
|
+
export interface ChatCandidateStore extends WriterLeash {
|
|
212
206
|
record(collection: string, results: readonly DocumentSearchResult[]): void;
|
|
213
207
|
/** Record every `listAssets` result into the flat library pool (EC-381). */
|
|
214
208
|
recordAssets(results: readonly AssetSearchResult[]): void;
|
|
215
|
-
/** Candidates for a target collection's relation fields, keyed by field name. */
|
|
216
|
-
candidatesFor(collection: CollectionDef): RelationCandidates;
|
|
217
|
-
/**
|
|
218
|
-
* Candidates for a target collection's asset/image fields (EC-381), keyed by
|
|
219
|
-
* field name — the one flat searched-asset pool (`listAssets` has no field
|
|
220
|
-
* dimension), filtered per field by that field's `accept` (EC-588). A field with no
|
|
221
|
-
* fitting candidate is absent, so it is omitted from the shape (empty beats wrong).
|
|
222
|
-
*/
|
|
223
|
-
assetCandidatesFor(collection: CollectionDef): AssetCandidates;
|
|
224
209
|
}
|
|
225
210
|
export declare function createChatCandidateStore(): ChatCandidateStore;
|
|
226
211
|
export interface ChatToolExecutorOptions {
|
|
@@ -249,8 +234,6 @@ export interface ChatToolExecutorOptions {
|
|
|
249
234
|
currentDocument?: () => CurrentDocumentRef | null | undefined;
|
|
250
235
|
/** Current knowledge snapshot (thunk — the body thunk refreshes it per request). */
|
|
251
236
|
knowledge?: () => ResolvedKnowledge | undefined;
|
|
252
|
-
/** Component manifests — context for `allow`-leashed richText/blocks fields. */
|
|
253
|
-
components?: readonly ComponentManifest[];
|
|
254
237
|
/** Target locale for localized fields. */
|
|
255
238
|
locale?: string;
|
|
256
239
|
/** Locale config — required for `translateDocument`. */
|
|
@@ -260,7 +243,9 @@ export interface ChatToolExecutorOptions {
|
|
|
260
243
|
* `gateValidateOptions(...)`, forwarded whole to every engine below. EC-473
|
|
261
244
|
* made the assistant's gate the editor's gate; passing one bag instead of five
|
|
262
245
|
* keys makes it stay that way, because a key can no longer be dropped by being
|
|
263
|
-
* forgotten at one of the three call sites this replaced.
|
|
246
|
+
* forgotten at one of the three call sites this replaced. Its `lookupManifest` is
|
|
247
|
+
* also how the writer-form converter and the read form reach component props
|
|
248
|
+
* (EC-593) — the props the validator judges, no second component source.
|
|
264
249
|
*/
|
|
265
250
|
validateOptions?: ValidateDocumentOptions;
|
|
266
251
|
/** Max repair attempts inside `applyContentWithShape`. */
|
|
@@ -272,16 +257,26 @@ export interface ChatToolExecutorOptions {
|
|
|
272
257
|
export interface ChatToolExecutor {
|
|
273
258
|
execute(call: ChatToolCall): Promise<ChatToolOutcome>;
|
|
274
259
|
}
|
|
260
|
+
/** A translate skip as one model-facing phrase: `menu[1].label (de): the provider returned no text`. */
|
|
261
|
+
export declare function describeTranslateSkip(skip: TranslateSkip): string;
|
|
275
262
|
/**
|
|
276
|
-
* The
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
* its `{ version,
|
|
281
|
-
*
|
|
282
|
-
*
|
|
263
|
+
* The `getDocument` output (EC-379 → EC-593): the document in the form the model reads
|
|
264
|
+
* — the ONE converter's read side (`toWriterDocument`), so rich text is a markdown
|
|
265
|
+
* string at EVERY depth where the engine's loss-guarded inverse can express it
|
|
266
|
+
* faithfully (a top-level field, an object sub-field, a repeater item, a component's
|
|
267
|
+
* rich-text prop), and keeps its stored `{ version: 2, content }` value otherwise (embeds,
|
|
268
|
+
* internal `ref` links, out-of-subset marks), so nothing the model later echoes back can
|
|
269
|
+
* silently lose structure. It used to project TOP-LEVEL rich text only (SHAPES #29: a
|
|
270
|
+
* nested value read as v2 while every writer was told markdown).
|
|
271
|
+
*
|
|
272
|
+
* `components` is the catalog's prop half (RULES F3d): for every component on the
|
|
273
|
+
* document, the props `updateFields` may change and the rules each value must satisfy,
|
|
274
|
+
* read off the same declarations the validator judges (`lookupManifest`). Applies to
|
|
275
|
+
* the TOOL OUTPUT only; the proposal/apply paths always read the raw stored document.
|
|
283
276
|
*/
|
|
284
|
-
export declare function
|
|
277
|
+
export declare function modelFacingDocument(document: CmsDocument, collection: CollectionDef, validateOptions?: ValidateDocumentOptions): CmsDocument & {
|
|
278
|
+
components?: Record<string, string[]>;
|
|
279
|
+
};
|
|
285
280
|
/**
|
|
286
281
|
* Build the client executor map. Every entry validates its input against
|
|
287
282
|
* {@link chatToolDefinitions}' zod schema (the route validates UIMessages only
|