Inline Text Edits Through the Widget
SenlerWidget.createTextEdit(config) requests a text change, returns a preview, and applies it after confirmation. Your site owns the buttons, loading state, comparison, and editor presentation. The method requires a compatible SDK and widget version.
Choose the Edit Scope First
scope: "selection"changes only the non-empty range returned bygetSelection().scope: "field"changes the entire field, including an empty one. This is the default.
Preserve the selection before focus is lost. start and end are UTF-16 offsets into exactly the string returned by getValue(), not a text-match search.
Create the Controller
Example for a textarea, after the widget is ready:
const field = document.querySelector("#description");
const editor = SenlerWidget.createTextEdit({
fieldId: "product:123:description",
getValue: () => field.value,
setValue: (value) => {
field.value = value;
field.dispatchEvent(new Event("input", { bubbles: true }));
},
getSelection: () => ({
start: field.selectionStart,
end: field.selectionEnd,
}),
});
async function improve() {
try {
const preview = await editor.generatePreview({
instruction: "Make the wording clearer.",
newDialog: true,
scope: "field",
});
showReview({
before: preview.sourceText,
after: preview.replacementText,
onAccept: () => {
try { editor.apply(preview); }
catch (error) { showError(error.message); }
},
});
} catch (error) {
showError(error.message);
}
}
showReview and showError are your site's UI functions, not widget methods. The example creates a separate dialog for each request. To reuse one, use getOrCreateDialog and pass its dialogId instead of newDialog.
Supply Field Data
fieldId: a non-empty stable field ID.getValue(): the complete current text.setValue(value): writes the accepted result into the editor.getSelection(): a{ start, end }range for selection editing.getRevision(): an optional editor-state revision that detects changes followed by undo.
An edit request includes the instruction and the requested text range, not the entire field when editing a selection. Pass additional information through request contextItems or context. Do not enable editing for passwords, secrets, or other data that must not reach the agent.
If getValue() returns Markdown, map the editor selection to source Markdown offsets. Rendered-text positions cannot index a string containing markup and escaping.
Start an Edit or Open Chat
generatePreview({ instruction, scope, ...options }) returns a Promise with the preview. It supports ask options except text: dialogId, newDialog, ref, context, cancellation, timeout, and callbacks.
The defaults are includeHistory: false and includeActions: false: previous messages are omitted from model input and registered site actions are not provided. This does not disable other agent tools or replace its system instruction. For predictable edits, use an agent that returns only the edited text.
To show the result's discussion, call SenlerWidget.selectDialog(preview.dialogId), then SenlerWidget.open(). Opening the chat alone does not start another edit.
Show and Apply the Preview
preview contains fieldId, requestId, dialogId, complete original sourceText, complete new replacementText, the selectedText, and its selectedTextReplacement.
The controller requires exactly one successful answer and does not change the field when the result arrives. Show a comparison, then call editor.apply(preview) after confirmation. For a selection, the rest of the source text stays unchanged.
Applying checks the current value and getRevision(), when provided. Stale, foreign, or already-applied previews are rejected. Do not copy the result directly into the field to bypass this check.
Handle States
Show loading while generatePreview is pending, then clear it on a result or error. onStatus, onChunk, and onAnswer provide intermediate updates; streaming fragments are not a completed edit.
invalid_selection: the selection is empty or invalid for the source string.invalid_preview: there is not exactly one successful answer, or this controller cannot apply the preview.stale_preview: the field changed after the request started.
Handle sending errors, cancellation, and timeouts as with ask. A request can be retried after an error; server-accepted work can continue after the client stops waiting.
Lifecycle
Call editor.destroy() when removing the field: the controller stops waiting for its requests and accepts no further edits. SenlerWidget.destroy() releases all controllers belonging to that instance. Each new edit captures the updated field value. Agent requests are unavailable in button_only mode.
Where to Find the Complete Contract
Public API describes instance methods; sending messages describes request results and errors. No special agent action or button is required to deliver a text preview.