Merge pull request 'fix: limit the prompt template to 1,000 characters' (#12) from fix/template-length-limit into develop
Reviewed-on: https://git.zavage.net/Zavage-Software/search-with-chatgpt-powered-by-openai-extension/pulls/12
This commit is contained in:
@@ -74,6 +74,7 @@ Open `about:addons`, select this extension, and choose the **Options** tab
|
||||
guarantee.
|
||||
- **Open in** — a new tab, a new background tab, or a new window.
|
||||
- **Prompt template** — wraps your text, for example `Explain simply: {query}`.
|
||||
Up to 1,000 characters.
|
||||
|
||||
Restore defaults resets extension preferences to Simple mode with translation
|
||||
hidden; it does not change Firefox's search engine or shortcut settings.
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
|
||||
export const OPEN_IN_VALUES = ["new-tab", "background-tab", "new-window"];
|
||||
|
||||
// In UTF-16 units, as maxlength counts. Keeps the template far inside
|
||||
// storage.sync's 8192-byte item quota even when every character is a pasted
|
||||
// control character (six bytes once JSON-escaped), and far beyond any template
|
||||
// the 8,000-character URL budget could send.
|
||||
export const MAX_TEMPLATE_CHARS = 1000;
|
||||
|
||||
export const DEFAULT_SETTINGS = {
|
||||
contextMenuMode: "simple",
|
||||
showTranslate: false,
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import { DEFAULT_SETTINGS, OPEN_IN_VALUES } from "./defaults.js";
|
||||
import { DEFAULT_SETTINGS, MAX_TEMPLATE_CHARS, OPEN_IN_VALUES } from "./defaults.js";
|
||||
|
||||
export function normalizeLanguage(value) {
|
||||
if (typeof value !== "string") return "";
|
||||
@@ -28,7 +28,7 @@ export function mergeSettings(stored) {
|
||||
if (OPEN_IN_VALUES.includes(stored.openIn)) {
|
||||
merged.openIn = stored.openIn;
|
||||
}
|
||||
if (typeof stored.promptTemplate === "string") {
|
||||
if (typeof stored.promptTemplate === "string" && stored.promptTemplate.length <= MAX_TEMPLATE_CHARS) {
|
||||
merged.promptTemplate = stored.promptTemplate;
|
||||
}
|
||||
return merged;
|
||||
|
||||
@@ -80,8 +80,8 @@
|
||||
|
||||
<div class="field">
|
||||
<label for="promptTemplate">Prompt template</label>
|
||||
<input type="text" id="promptTemplate" spellcheck="false" />
|
||||
<p class="hint"><code>{query}</code> is replaced with your selected text. Used by Ask normally, Simple mode, the toolbar button, and the keyboard shortcut. Other advanced actions use their own prompts.</p>
|
||||
<input type="text" id="promptTemplate" spellcheck="false" maxlength="1000" />
|
||||
<p class="hint"><code>{query}</code> is replaced with your selected text. Used by Ask normally, Simple mode, the toolbar button, and the keyboard shortcut. Other advanced actions use their own prompts. Up to 1,000 characters.</p>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
|
||||
+27
-1
@@ -1,7 +1,9 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import { DEFAULT_SETTINGS } from "../lib/defaults.js";
|
||||
import { readFileSync } from "node:fs";
|
||||
|
||||
import { DEFAULT_SETTINGS, MAX_TEMPLATE_CHARS } from "../lib/defaults.js";
|
||||
import { mergeSettings } from "../lib/settings.js";
|
||||
|
||||
test("empty object yields the defaults", () => {
|
||||
@@ -67,6 +69,30 @@ test("wrong types fall back to the default", () => {
|
||||
assert.equal(merged.promptTemplate, DEFAULT_SETTINGS.promptTemplate);
|
||||
});
|
||||
|
||||
test("a prompt template over the length limit falls back to the default", () => {
|
||||
assert.equal(typeof MAX_TEMPLATE_CHARS, "number");
|
||||
const atLimit = "x".repeat(MAX_TEMPLATE_CHARS);
|
||||
assert.equal(mergeSettings({ promptTemplate: atLimit }).promptTemplate, atLimit);
|
||||
assert.equal(mergeSettings({ promptTemplate: `${atLimit}x` }).promptTemplate,
|
||||
DEFAULT_SETTINGS.promptTemplate);
|
||||
});
|
||||
|
||||
// storage.sync rejects any item over 8192 bytes (key plus JSON value), and the
|
||||
// options page writes every field in one set(), so one oversized template would
|
||||
// make every later save fail. The worst character is a pasted control
|
||||
// character, which JSON escapes to six bytes.
|
||||
test("a template at the limit fits storage.sync's per-item quota in the worst case", () => {
|
||||
const worst = "\u0001".repeat(MAX_TEMPLATE_CHARS);
|
||||
const bytes = new TextEncoder().encode("promptTemplate" + JSON.stringify(worst)).length;
|
||||
assert.ok(bytes <= 8192, `${bytes} bytes`);
|
||||
});
|
||||
|
||||
test("the options page enforces the same template limit", () => {
|
||||
const html = readFileSync(new URL("../options/options.html", import.meta.url), "utf8");
|
||||
const input = html.match(/<input[^>]*id="promptTemplate"[^>]*>/)?.[0] ?? "";
|
||||
assert.equal(input.match(/maxlength="(\d+)"/)?.[1], String(MAX_TEMPLATE_CHARS));
|
||||
});
|
||||
|
||||
test("an out-of-range openIn falls back to the default", () => {
|
||||
assert.equal(mergeSettings({ openIn: "teleport" }).openIn, DEFAULT_SETTINGS.openIn);
|
||||
assert.equal(mergeSettings({ openIn: "" }).openIn, DEFAULT_SETTINGS.openIn);
|
||||
|
||||
Reference in New Issue
Block a user