@simmalugnt-se/payload-editor-assistant 0.3.0 → 0.3.1

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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.1
4
+
5
+ - A greeting or a question no longer fills empty fields: the assistant fills them only when asked.
6
+ Before, "hello" on a page with an empty field could come back as a proposal.
7
+ - The follow-up that makes the model stage a change it only talked about now needs a request for a
8
+ change (or a yes) from the editor; a question it asks after a greeting is left as a question.
9
+ - While the assistant works, Send turns into Stop instead of a separate button in the thread.
10
+
3
11
  ## 0.3.0
4
12
 
5
13
  - Keep or undo: a proposed form change goes into the form right away, so the fields and Live Preview
@@ -339,13 +339,15 @@ export function EditorAssistantAside() {
339
339
  }
340
340
  return (_jsxs("aside", { className: "ea-aside", "aria-label": copy.assistant, [KEEP_SELECTION_ATTR]: "", children: [_jsxs("div", { className: "ea-aside__head", children: [_jsxs("div", { className: "ea-aside__title", children: [_jsx("h2", { children: copy.assistant }), bridge ? _jsx("p", { className: "ea-aside__context", children: contextLine(bridge, config) }) : null] }), (messages.length > 0 || pendingApproval) && !pendingApproval?.applied ? (_jsx(Button, { buttonStyle: "subtle", margin: false, onClick: () => resetConversation(), size: "medium", children: copy.newChat })) : null, _jsx(Button, { "aria-label": copy.collapseLabel, buttonStyle: "icon-label", className: "ea-aside__collapse", icon: _jsx(ChevronIcon, { direction: "right" }), margin: false, onClick: () => setCollapsed(true), tooltip: copy.collapse })] }), _jsxs("div", { className: "ea-aside__body", children: [_jsxs("div", { className: "ea-messages", ref: threadRef, onScroll: onThreadScroll, children: [messages.length === 0 ? (_jsx("div", { className: "ea-msg ea-msg--assistant", children: introText(view, bridge, collections, config, copy) })) : null, messages.map((message) => (_jsxs("div", { className: `ea-msg ea-msg--${message.role}`, children: [message.text, message.candidates?.length ? (_jsx("div", { className: "ea-actions", children: message.candidates.map((candidate) => (_jsx(Button, { buttonStyle: "pill", margin: false, onClick: () => {
341
341
  router.push(candidate.href);
342
- }, size: "small", children: candidate.label }, candidate.href))) })) : null] }, message.id))), status === "streaming" ? (_jsxs("div", { className: "ea-msg ea-msg--working", children: [_jsxs("span", { className: "ea-dots", "aria-hidden": "true", children: [_jsx("span", {}), _jsx("span", {}), _jsx("span", {})] }), _jsx("span", { children: copy.working }), _jsx(Button, { buttonStyle: "subtle", margin: false, onClick: () => stop(), size: "small", children: copy.stop })] })) : null] }), pendingApproval ? (_jsxs("div", { className: "ea-approval", children: [_jsx("h3", { children: pendingApproval.title }), pendingApproval.applied ? (_jsx("p", { className: "ea-approval__hint", children: autosave ? copy.previewHintAutosave : copy.previewHint })) : null, _jsx("ul", { className: "ea-approval__diff", children: pendingApproval.summary.split("\n").map((line, index) => line.startsWith(" ") ? (
342
+ }, size: "small", children: candidate.label }, candidate.href))) })) : null] }, message.id))), status === "streaming" ? (_jsxs("div", { className: "ea-msg ea-msg--working", children: [_jsxs("span", { className: "ea-dots", "aria-hidden": "true", children: [_jsx("span", {}), _jsx("span", {}), _jsx("span", {})] }), _jsx("span", { children: copy.working })] })) : null] }), pendingApproval ? (_jsxs("div", { className: "ea-approval", children: [_jsx("h3", { children: pendingApproval.title }), pendingApproval.applied ? (_jsx("p", { className: "ea-approval__hint", children: autosave ? copy.previewHintAutosave : copy.previewHint })) : null, _jsx("ul", { className: "ea-approval__diff", children: pendingApproval.summary.split("\n").map((line, index) => line.startsWith(" ") ? (
343
343
  // biome-ignore lint/suspicious/noArrayIndexKey: lines are static for one approval
344
344
  _jsx("li", { className: "ea-approval__sub", children: line.trim() }, index)) : (
345
345
  // biome-ignore lint/suspicious/noArrayIndexKey: lines are static for one approval
346
346
  _jsx("li", { children: line }, index))) }), confirmUndo ? (_jsxs(_Fragment, { children: [_jsx("p", { className: "ea-approval__warn", children: copy.undoLosesEdits }), _jsxs("div", { className: "ea-actions", children: [_jsx(Button, { buttonStyle: "primary", margin: false, onClick: () => void undoPreview(pendingApproval, true), size: "medium", children: copy.undoAnyway }), _jsx(Button, { buttonStyle: "secondary", margin: false, onClick: () => setConfirmUndo(false), size: "medium", children: copy.cancel })] })] })) : (_jsxs("div", { className: "ea-actions", children: [_jsx(Button, { buttonStyle: "primary", margin: false, onClick: () => void decide("approve"), size: "medium", children: pendingApproval.applied ? copy.keep : copy.approve }), _jsx(Button, { buttonStyle: "secondary", margin: false, onClick: () => void decide("reject"), size: "medium", children: pendingApproval.applied ? copy.undo : copy.reject })] }))] })) : null, status !== "idle" && status !== "streaming" ? (_jsx("div", { className: `ea-status ea-status--${status}`, children: statusText(status, copy) })) : null, _jsxs("form", { className: "ea-composer", onSubmit: onSubmit, children: [visibleShortcuts.length > 0 ? (_jsx("div", { className: "ea-shortcuts", children: visibleShortcuts.map((shortcut) => (_jsx(Button, { buttonStyle: "pill", disabled: status === "streaming", margin: false, onClick: () => {
347
347
  void send(shortcut.prompt);
348
- }, size: "small", children: shortcut.label }, shortcut.id))) })) : null, selection && bridge ? (_jsxs("div", { className: "ea-selection", children: [_jsxs("span", { className: "ea-selection__label", children: [copy.selected, ": ", _jsx("strong", { children: selection.label })] }), _jsx("button", { "aria-label": copy.clearSelection, className: "ea-selection__clear", type: "button", onClick: () => setSelection(null), children: _jsx(XIcon, {}) })] })) : null, _jsxs("div", { className: "ea-composer__box", children: [_jsx("textarea", { disabled: status === "streaming", placeholder: copy.placeholder, rows: 2, value: draft, onChange: (event) => setDraft(event.target.value), onKeyDown: onKeyDown }), _jsx("div", { className: "ea-composer__bar", children: _jsx(Button, { buttonStyle: "primary", disabled: status === "streaming" || draft.trim() === "", margin: false, size: "medium", type: "submit", children: copy.send }) })] })] })] })] }));
348
+ }, size: "small", children: shortcut.label }, shortcut.id))) })) : null, selection && bridge ? (_jsxs("div", { className: "ea-selection", children: [_jsxs("span", { className: "ea-selection__label", children: [copy.selected, ": ", _jsx("strong", { children: selection.label })] }), _jsx("button", { "aria-label": copy.clearSelection, className: "ea-selection__clear", type: "button", onClick: () => setSelection(null), children: _jsx(XIcon, {}) })] })) : null, _jsxs("div", { className: "ea-composer__box", children: [_jsx("textarea", { disabled: status === "streaming", placeholder: copy.placeholder, rows: 2, value: draft, onChange: (event) => setDraft(event.target.value), onKeyDown: onKeyDown }), _jsx("div", { className: "ea-composer__bar", children: status === "streaming" ? (
349
+ // While the assistant works, Send becomes Stop, where the editor's eye already is.
350
+ _jsx(Button, { "aria-label": copy.stop, buttonStyle: "secondary", className: "ea-composer__stop", icon: _jsx("span", { className: "ea-stop-icon", "aria-hidden": "true" }), iconPosition: "left", margin: false, onClick: () => stop(), size: "medium", type: "button", children: copy.stop })) : (_jsx(Button, { buttonStyle: "primary", disabled: draft.trim() === "", margin: false, size: "medium", type: "submit", children: copy.send })) })] })] })] })] }));
349
351
  }
350
352
  /** "Page · Home", with the locale when the project has more than one. */
351
353
  function contextLine(bridge, config) {
@@ -10,8 +10,9 @@ export function claimedUnstagedChange(text) {
10
10
  export function offeredValue(text, request) {
11
11
  return QUOTED.test(text) && ASKS_FOR_CHANGE.test(request);
12
12
  }
13
- // Letter lookarounds rather than \b, which treats å, ä and ö as word boundaries.
14
- const ASKS_FOR_CHANGE = /(?<!\p{L})(make|change|rewrite|write|add|replace|shorten|tighten|fill|translate|update|improve|set|rename|remove|delete|gör|göra|ändra|skriv|skriva|lägg|lägga|byt|byta|korta|fyll|fylla|översätt|uppdatera|förbättra|sätt|ta bort)(?!\p{L})/iu;
13
+ // A request for a change, or a yes to one the assistant asked about. Letter lookarounds rather
14
+ // than \b, which treats å, ä and ö as word boundaries.
15
+ const ASKS_FOR_CHANGE = /(?<!\p{L})(make|change|rewrite|write|add|replace|shorten|tighten|fill|translate|update|improve|set|rename|remove|delete|yes|yeah|sure|ok|okay|do it|go ahead|gör|göra|ändra|skriv|skriva|lägg|lägga|byt|byta|korta|fyll|fylla|översätt|uppdatera|förbättra|sätt|ta bort|ja|japp|kör|gärna)(?!\p{L})/iu;
15
16
  const QUOTED = /["“”«»][^"“”«»]{2,}["“”«»]|'[^']{2,}'/;
16
17
  const CLAIMED_CHANGE = /godkänn|godkann|approve|rubriken är nu|the headline is now|sparas den på sidan|fälten i på sidan|pending form change|i've applied|i have applied/i;
17
18
  const ASKED_TO_MUTATE = /ska jag (lägga|fylla|ändra|sätta|uppdatera)|should i (put|fill|change|set|update|apply)|shall i (put|fill|change|set|update|apply)|want me to (put|fill|change|set|update|apply)/i;
@@ -19,5 +20,10 @@ export function needsProposeRetry(input) {
19
20
  if (!input.hasOpenDocument || input.pendingApproval || input.navigate) {
20
21
  return false;
21
22
  }
22
- return claimedUnstagedChange(input.text) || offeredValue(input.text, input.request ?? "");
23
+ const request = input.request ?? "";
24
+ // A claim that the change is made is wrong whatever was asked; asking for permission or writing
25
+ // a value out is only a missed proposal when a change was asked for.
26
+ return (CLAIMED_CHANGE.test(input.text) ||
27
+ (ASKS_FOR_CHANGE.test(request) && ASKED_TO_MUTATE.test(input.text)) ||
28
+ offeredValue(input.text, request));
23
29
  }
@@ -90,7 +90,7 @@ function thisTurnBlock(bridge, turnContext) {
90
90
  if (source) {
91
91
  lines.push(source);
92
92
  }
93
- lines.push("If the editor wants those filled, call form.propose now with text in the open language. Do not ask.");
93
+ lines.push("Fill them only when the editor asks for that (fill in, translate, write, fyll i, översätt). A greeting, a question or small talk is not such a request: answer it and propose nothing. When they do ask, call form.propose now with text in the open language. Do not ask.");
94
94
  }
95
95
  }
96
96
  return `\n\n${lines.join(" ")}`;
@@ -389,3 +389,11 @@ html[data-theme="dark"] .ea-aside {
389
389
  .ea-trigger {
390
390
  margin-inline: 8px;
391
391
  }
392
+
393
+ .ea-stop-icon {
394
+ display: block;
395
+ width: 9px;
396
+ height: 9px;
397
+ border-radius: 2px;
398
+ background: currentColor;
399
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simmalugnt-se/payload-editor-assistant",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Context-aware editor assistant plugin for Payload Admin",
5
5
  "keywords": [
6
6
  "payload",