pict-section-prompteditor 1.0.0 → 1.1.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/README.md
CHANGED
|
@@ -9,6 +9,7 @@ A prompt crafting and management section for the [Pict](https://github.com/fable
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
11
|
- Typed prompts with markdown segments (Context / Request / Success Criteria and friends), plus **fixed preamble** segments for locked team standards
|
|
12
|
+
- A per-prompt "segment headings in the output" toggle, saved with the prompt: on for structured documents (`## Context` above each block), off for bare bodies
|
|
12
13
|
- Weighted word list matrices: `[["Tyrannosaurus", 3], ["Diplodocus", 1]]` draws 75/25, with live share percentages as you curate
|
|
13
14
|
- The `{~WordListEntry:Name~}` template expression (short form `{~WLE:~}`), with an optional miss default: `{~WLE:Name:fallback~}`
|
|
14
15
|
- Generation runs the **real pict template engine**, so every pict expression works inside a prompt
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pict-section-prompteditor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Prompt crafting and management section for Pict: typed prompts with segments (context, request, success criteria), curated word list matrices with weights, a {~WordListEntry:Name~} template expression for weighted-random generation, batch generation with zip download, and a pluggable data provider that defaults to in-memory AppData.",
|
|
5
5
|
"main": "source/Pict-Section-PromptEditor.js",
|
|
6
6
|
"files": [
|
|
@@ -31,6 +31,12 @@ function slug(pText)
|
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Assemble a prompt's markdown source from its type's segments.
|
|
34
|
+
*
|
|
35
|
+
* Segment headings (## Context and friends) are on by default; a prompt that
|
|
36
|
+
* carries IncludeSegmentHeadings: false compiles bare segment bodies instead,
|
|
37
|
+
* so the author decides per prompt whether the structure shows in the output.
|
|
38
|
+
* The document title heading stays governed by the IncludeTitleHeading option.
|
|
39
|
+
*
|
|
34
40
|
* @param {object} pPrompt - the prompt record
|
|
35
41
|
* @param {object} pType - the resolved prompt type
|
|
36
42
|
* @param {object} [pOptions] - { IncludeTitleHeading: true, SegmentHeadingLevel: 2 }
|
|
@@ -40,6 +46,7 @@ function assembleSource(pPrompt, pType, pOptions)
|
|
|
40
46
|
{
|
|
41
47
|
let tmpOptions = pOptions || {};
|
|
42
48
|
let tmpIncludeTitle = (typeof tmpOptions.IncludeTitleHeading === 'undefined') ? true : !!tmpOptions.IncludeTitleHeading;
|
|
49
|
+
let tmpIncludeSegmentHeadings = !(pPrompt && pPrompt.IncludeSegmentHeadings === false);
|
|
43
50
|
let tmpHeading = '#'.repeat(Math.max(1, Math.min(6, Number(tmpOptions.SegmentHeadingLevel) || 2)));
|
|
44
51
|
let tmpSegments = (pType && Array.isArray(pType.Segments)) ? pType.Segments : [];
|
|
45
52
|
let tmpBodies = (pPrompt && pPrompt.Segments) ? pPrompt.Segments : {};
|
|
@@ -60,7 +67,9 @@ function assembleSource(pPrompt, pType, pOptions)
|
|
|
60
67
|
if (tmpSegment.Optional || tmpSegment.Fixed) { continue; }
|
|
61
68
|
tmpBody = '(nothing written for this segment yet)';
|
|
62
69
|
}
|
|
63
|
-
tmpParts.push(
|
|
70
|
+
tmpParts.push(tmpIncludeSegmentHeadings
|
|
71
|
+
? (tmpHeading + ' ' + String(tmpSegment.Name || tmpSegment.Key) + '\n\n' + tmpBody)
|
|
72
|
+
: tmpBody);
|
|
64
73
|
}
|
|
65
74
|
|
|
66
75
|
return tmpParts.join('\n\n') + '\n';
|
|
@@ -16,9 +16,11 @@
|
|
|
16
16
|
* drawn by {~WordListEntry:Name~} is weight / sum(weights).
|
|
17
17
|
*
|
|
18
18
|
* Prompt { Key, Title, TypeKey, Segments: { segmentKey: markdown },
|
|
19
|
-
* Author, Meta, CreatedAt, UpdatedAt }
|
|
19
|
+
* IncludeSegmentHeadings, Author, Meta, CreatedAt, UpdatedAt }
|
|
20
20
|
* A crafted prompt. Segments hold the markdown for each of the prompt
|
|
21
|
-
* type's segments, keyed by segment Key.
|
|
21
|
+
* type's segments, keyed by segment Key. IncludeSegmentHeadings (default
|
|
22
|
+
* true) decides whether the compiler writes the ## segment headings above
|
|
23
|
+
* each body in the assembled output. Meta is an opaque object the
|
|
22
24
|
* provider round-trips untouched -- the seam where a host hangs ratings,
|
|
23
25
|
* version pointers, or anything else.
|
|
24
26
|
*
|
|
@@ -208,6 +210,7 @@ class InMemoryPromptProvider extends PromptDataProvider
|
|
|
208
210
|
Title: String(tmpDraft.Title || 'Untitled prompt'),
|
|
209
211
|
TypeKey: String(tmpDraft.TypeKey),
|
|
210
212
|
Segments: (tmpDraft.Segments && typeof tmpDraft.Segments === 'object') ? this._clone(tmpDraft.Segments) : {},
|
|
213
|
+
IncludeSegmentHeadings: (tmpDraft.IncludeSegmentHeadings === false) ? false : true,
|
|
211
214
|
Author: tmpDraft.Author || null,
|
|
212
215
|
Meta: (typeof tmpDraft.Meta === 'undefined') ? {} : this._clone(tmpDraft.Meta),
|
|
213
216
|
CreatedAt: tmpNow,
|
|
@@ -225,6 +228,7 @@ class InMemoryPromptProvider extends PromptDataProvider
|
|
|
225
228
|
if (typeof tmpPatch.Title !== 'undefined') { tmpPrompt.Title = String(tmpPatch.Title); }
|
|
226
229
|
if (typeof tmpPatch.TypeKey !== 'undefined') { tmpPrompt.TypeKey = String(tmpPatch.TypeKey); }
|
|
227
230
|
if (typeof tmpPatch.Segments !== 'undefined') { tmpPrompt.Segments = this._clone(tmpPatch.Segments || {}); }
|
|
231
|
+
if (typeof tmpPatch.IncludeSegmentHeadings !== 'undefined') { tmpPrompt.IncludeSegmentHeadings = (tmpPatch.IncludeSegmentHeadings === false) ? false : true; }
|
|
228
232
|
if (typeof tmpPatch.Meta !== 'undefined') { tmpPrompt.Meta = this._clone(tmpPatch.Meta); }
|
|
229
233
|
tmpPrompt.UpdatedAt = this._now();
|
|
230
234
|
return Promise.resolve(this._clone(tmpPrompt));
|
|
@@ -136,6 +136,8 @@ const _DefaultConfiguration =
|
|
|
136
136
|
.pspe-editor-head { display: flex; gap: 8px; align-items: center; margin-bottom: 12px; flex-wrap: wrap; }
|
|
137
137
|
.pspe-editor-title { flex: 1; min-width: 200px; font-weight: 650; font-size: 15px; }
|
|
138
138
|
.pspe-type-desc { font-size: 12px; color: var(--theme-color-text-muted, #97a1ab); margin: -6px 0 12px; }
|
|
139
|
+
.pspe-editor-opts { margin: -4px 0 12px; }
|
|
140
|
+
.pspe-editor-opt { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--theme-color-text-muted, #97a1ab); cursor: pointer; user-select: none; }
|
|
139
141
|
|
|
140
142
|
.pspe-segment {
|
|
141
143
|
border: 1px solid var(--theme-color-border-light, #e7ecf0); border-radius: 10px;
|
|
@@ -254,6 +256,7 @@ const _DefaultConfiguration =
|
|
|
254
256
|
{~TS:PromptEditor-PromptActions:Record.ActionsSlot~}
|
|
255
257
|
</div>
|
|
256
258
|
<div class="pspe-type-desc">{~D:Record.TypeDescription~}</div>
|
|
259
|
+
{~TS:PromptEditor-EditorOptions:Record.OptionsSlot~}
|
|
257
260
|
{~TS:PromptEditor-Segment:Record.Segments~}
|
|
258
261
|
{~TS:PromptEditor-GenerateBar:Record.GenerateSlot~}
|
|
259
262
|
{~TS:PromptEditor-PreviewPanel:Record.PreviewPanelSlot~}`
|
|
@@ -282,6 +285,17 @@ const _DefaultConfiguration =
|
|
|
282
285
|
Hash: 'PromptEditor-PromptActions',
|
|
283
286
|
Template: /*html*/`<button class="pspe-btn pspe-btn-sm" title="Duplicate this prompt" onclick="_Pict.views['{~D:Record.ViewHash~}'].duplicatePrompt()">Duplicate</button><button class="pspe-btn pspe-btn-sm pspe-btn-danger" onclick="_Pict.views['{~D:Record.ViewHash~}'].deletePrompt()">Delete</button>`
|
|
284
287
|
},
|
|
288
|
+
{
|
|
289
|
+
Hash: 'PromptEditor-EditorOptions',
|
|
290
|
+
Template: /*html*/`
|
|
291
|
+
<div class="pspe-editor-opts">
|
|
292
|
+
<label class="pspe-editor-opt" title="When off, the assembled prompt is just the segment bodies, no ## headings above them.">
|
|
293
|
+
<input type="checkbox" {~D:Record.SegmentHeadingsChecked~}
|
|
294
|
+
onchange="_Pict.views['{~D:Record.ViewHash~}'].setSegmentHeadings(this.checked)">
|
|
295
|
+
Segment headings in the output
|
|
296
|
+
</label>
|
|
297
|
+
</div>`
|
|
298
|
+
},
|
|
285
299
|
{
|
|
286
300
|
Hash: 'PromptEditor-Segment',
|
|
287
301
|
Template: /*html*/`
|
|
@@ -909,6 +923,11 @@ class PictViewPromptEditor extends libPictView
|
|
|
909
923
|
SelectedAttr: (pTypeOption.Key === pPrompt.TypeKey) ? 'selected' : ''
|
|
910
924
|
})),
|
|
911
925
|
ActionsSlot: pReadOnly ? [] : [{ ViewHash: this.Hash }],
|
|
926
|
+
OptionsSlot: pReadOnly ? [] :
|
|
927
|
+
[{
|
|
928
|
+
ViewHash: this.Hash,
|
|
929
|
+
SegmentHeadingsChecked: (pPrompt.IncludeSegmentHeadings === false) ? '' : 'checked'
|
|
930
|
+
}],
|
|
912
931
|
Segments: tmpSegments,
|
|
913
932
|
GenerateSlot: pReadOnly ? [] :
|
|
914
933
|
[{
|
|
@@ -1077,6 +1096,7 @@ class PictViewPromptEditor extends libPictView
|
|
|
1077
1096
|
TypeKey: tmpPrompt.TypeKey,
|
|
1078
1097
|
Title: tmpPrompt.Title + ' (copy)',
|
|
1079
1098
|
Segments: JSON.parse(JSON.stringify(tmpPrompt.Segments || {})),
|
|
1099
|
+
IncludeSegmentHeadings: tmpPrompt.IncludeSegmentHeadings !== false,
|
|
1080
1100
|
Meta: JSON.parse(JSON.stringify(tmpPrompt.Meta || {})),
|
|
1081
1101
|
Author: this.options.CurrentUser
|
|
1082
1102
|
})
|
|
@@ -1123,6 +1143,24 @@ class PictViewPromptEditor extends libPictView
|
|
|
1123
1143
|
.catch((pError) => this._toast('Segment save failed: ' + pError.message, 'error'));
|
|
1124
1144
|
}
|
|
1125
1145
|
|
|
1146
|
+
// The per-prompt "segment headings in the output" toggle: saves with the
|
|
1147
|
+
// prompt, and the compiler reads it on every assemble (preview, generate,
|
|
1148
|
+
// zip). No re-render needed - the checkbox itself holds the new state -
|
|
1149
|
+
// but an open preview re-rolls so what you see matches what you would get.
|
|
1150
|
+
setSegmentHeadings(pChecked)
|
|
1151
|
+
{
|
|
1152
|
+
let tmpPrompt = this._activePrompt();
|
|
1153
|
+
if (!tmpPrompt) { return; }
|
|
1154
|
+
tmpPrompt.IncludeSegmentHeadings = !!pChecked;
|
|
1155
|
+
this._provider.updatePrompt(tmpPrompt.Key, { IncludeSegmentHeadings: !!pChecked })
|
|
1156
|
+
.then((pSaved) =>
|
|
1157
|
+
{
|
|
1158
|
+
this._fire('onPromptSaved', pSaved);
|
|
1159
|
+
if (this._ui.Preview && this._ui.Preview.PromptKey === tmpPrompt.Key) { this.previewOnce(); }
|
|
1160
|
+
})
|
|
1161
|
+
.catch((pError) => this._toast('Save failed: ' + pError.message, 'error'));
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1126
1164
|
toggleSegmentPreview(pSegmentKey)
|
|
1127
1165
|
{
|
|
1128
1166
|
let tmpPrompt = this._activePrompt();
|