feat(quick-pane): add follow-up chat renewal
This commit is contained in:
+74
-12
@@ -2,7 +2,7 @@ import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import test from "node:test";
|
||||
|
||||
test("Quick Pane polls snapshots, renders answers, and gates handoff", async () => {
|
||||
test("Quick Pane polls snapshots, renders answers, and gates manual transcript handoff", async () => {
|
||||
const source = await readFile(
|
||||
new URL("../ui/src/quick-pane/QuickPane.tsx", import.meta.url),
|
||||
"utf8",
|
||||
@@ -11,10 +11,10 @@ test("Quick Pane polls snapshots, renders answers, and gates handoff", async ()
|
||||
assert.match(source, /setInterval\(\(\) => void refresh\(\), 800\)/);
|
||||
assert.match(source, /<ReactMarkdown remarkPlugins=\{\[remarkGfm\]\}>/);
|
||||
assert.match(source, /className="quick-pane-notice escalation"/);
|
||||
assert.match(
|
||||
source,
|
||||
/<button type="button" onClick=\{continueFull\}>\s*Continue\s*<\/button>/,
|
||||
);
|
||||
assert.match(source, /className="quick-pane-notice continue"/);
|
||||
assert.match(source, /Continue in full session/);
|
||||
assert.match(source, /Quick Pane transcript:/);
|
||||
assert.doesNotMatch(source, /maximumSeconds|Quick time budget/);
|
||||
});
|
||||
|
||||
test("main Settings uses shared catalog selectors with provider derived from models", async () => {
|
||||
@@ -46,19 +46,46 @@ test("main Settings uses shared catalog selectors with provider derived from mod
|
||||
assert.match(pane, /preparedRuntimeRef/);
|
||||
assert.doesNotMatch(pane, /get_model_catalog/);
|
||||
assert.match(pane, /set_thinking_level/);
|
||||
assert.match(pane, /Loading models…/);
|
||||
assert.match(pane, /catalogStatus !== "ready"/);
|
||||
assert.doesNotMatch(pane, /showSettings/);
|
||||
assert.doesNotMatch(pane, /Save Quick Pane settings/);
|
||||
assert.match(pane, /isStreaming === false/);
|
||||
assert.match(pane, /!snapshotIsActive\(snapshot\)/);
|
||||
assert.match(pane, /current === submitted\.request \? "" : current/);
|
||||
assert.match(pane, /readOnly=\{runActive\}/);
|
||||
assert.match(pane, /window\.requestAnimationFrame\(focusInput\)/);
|
||||
assert.match(pane, /\.slice\(0, 5\)/);
|
||||
assert.match(pane, /aria-label="Answer history"/);
|
||||
assert.doesNotMatch(pane, /\.slice\(0, 5\)/);
|
||||
assert.doesNotMatch(pane, /aria-label="Answer history"/);
|
||||
assert.match(
|
||||
pane,
|
||||
/transcriptMessages\(snapshot, submittedPromptRequestsRef\.current\)/,
|
||||
);
|
||||
assert.match(pane, /const QUICK_PANE_ADVISORY_PREFIX =/);
|
||||
assert.match(pane, /submittedPromptRequests\.get\(text\)/);
|
||||
assert.match(
|
||||
pane,
|
||||
/text\.startsWith\(QUICK_PANE_ADVISORY_PREFIX\) \? "" : text/,
|
||||
);
|
||||
assert.match(
|
||||
pane,
|
||||
/submittedPromptRequestsRef\.current\.set\(guardrails, submittedRequest\)/,
|
||||
);
|
||||
assert.match(pane, /submittedPromptRequestsRef\.current\.clear\(\)/);
|
||||
assert.doesNotMatch(
|
||||
pane,
|
||||
/delimiterIndex|text\.indexOf\(USER_REQUEST_DELIMITER\)/,
|
||||
);
|
||||
assert.match(
|
||||
pane,
|
||||
/message\.role !== "user" && message\.role !== "assistant"/,
|
||||
);
|
||||
assert.match(pane, /lastUserQuestionAtRef\.current = submittedAt/);
|
||||
assert.match(pane, /lastCompletedAnswerAtRef\.current = Date\.now\(\)/);
|
||||
assert.doesNotMatch(pane, /localStorage|sessionStorage|save_ui_state/);
|
||||
assert.match(persistence, /quickPane: current\.quickPane/);
|
||||
});
|
||||
|
||||
test("Quick Pane keeps slash-containing model IDs atomic and reloads catalog on focus", async () => {
|
||||
test("Quick Pane keeps slash-containing model IDs atomic and renews catalog on focus", async () => {
|
||||
const [pane, catalog] = await Promise.all([
|
||||
readFile(
|
||||
new URL("../ui/src/quick-pane/QuickPane.tsx", import.meta.url),
|
||||
@@ -70,7 +97,16 @@ test("Quick Pane keeps slash-containing model IDs atomic and reloads catalog on
|
||||
assert.match(pane, /provider: submittedModel\.provider/);
|
||||
assert.match(pane, /modelId: submittedModel\.modelId/);
|
||||
assert.doesNotMatch(pane, /selectedModel\.split/);
|
||||
assert.match(pane, /onFocusChanged[\s\S]*?void prepareRuntime\(\)/);
|
||||
assert.match(pane, /onFocusChanged[\s\S]*?void renewChatOnFocus\(\)/);
|
||||
assert.match(pane, /if \(!event\.payload\) return;/);
|
||||
assert.match(pane, /const CHAT_RENEWAL_MS = 180_000/);
|
||||
assert.match(pane, /Date\.now\(\) - lastActivity > CHAT_RENEWAL_MS/);
|
||||
assert.match(pane, /event\.ctrlKey && event\.key\.toLowerCase\(\) === "n"/);
|
||||
assert.match(pane, /event\.preventDefault\(\)/);
|
||||
assert.doesNotMatch(
|
||||
pane,
|
||||
/setInterval[^\n]*CHAT_RENEWAL_MS|setTimeout[^\n]*CHAT_RENEWAL_MS/,
|
||||
);
|
||||
assert.match(
|
||||
catalog,
|
||||
/JSON\.stringify\(\[identity\.provider, identity\.modelId\]\)/,
|
||||
@@ -88,6 +124,11 @@ test("Quick Pane dismiss and mutually exclusive window visibility stay native-se
|
||||
]);
|
||||
assert.match(pane, /invoke\("dismiss_quick_pane"\)/);
|
||||
assert.doesNotMatch(pane, /getCurrentWindow\(\)\.hide\(\)/);
|
||||
const dismissPane = pane.slice(
|
||||
pane.indexOf("const dismissPane"),
|
||||
pane.indexOf("const clearChatState"),
|
||||
);
|
||||
assert.doesNotMatch(dismissPane, /closeRuntime|clearRuntime|prepareRuntime/);
|
||||
assert.match(nativeSource, /fn dismiss_quick_pane\(/);
|
||||
assert.match(
|
||||
nativeSource,
|
||||
@@ -165,9 +206,17 @@ test("Quick Pane uses native dimensions and request-first compact layout", async
|
||||
{
|
||||
width: quickPane.width,
|
||||
height: quickPane.height,
|
||||
minWidth: quickPane.minWidth,
|
||||
minHeight: quickPane.minHeight,
|
||||
transparent: quickPane.transparent,
|
||||
},
|
||||
{ width: 640, height: 440, transparent: true },
|
||||
{
|
||||
width: 640,
|
||||
height: 360,
|
||||
minWidth: 520,
|
||||
minHeight: 360,
|
||||
transparent: true,
|
||||
},
|
||||
);
|
||||
assert.ok(capability.windows.includes("quick-pane"));
|
||||
assert.match(nativeSource, /WindowEvent::CloseRequested/);
|
||||
@@ -177,6 +226,10 @@ test("Quick Pane uses native dimensions and request-first compact layout", async
|
||||
/WebviewWindowBuilder::from_config\(app, config\)/,
|
||||
);
|
||||
assert.match(nativeSource, /get_or_create_quick_pane/);
|
||||
assert.match(nativeSource, /fn resize_quick_pane/);
|
||||
assert.match(nativeSource, /height\.clamp\(360\.0, 520\.0\)/);
|
||||
assert.match(source, /new ResizeObserver\(resizeToContent\)/);
|
||||
assert.match(source, /invoke\("resize_quick_pane", \{ height \}\)/);
|
||||
assert.doesNotMatch(source, /onCloseRequested/);
|
||||
assert.match(source, /className="quick-pane-request"/);
|
||||
assert.match(source, /className="quick-pane-exchange"/);
|
||||
@@ -200,7 +253,8 @@ test("Quick Pane uses native dimensions and request-first compact layout", async
|
||||
);
|
||||
assert.match(stylesheet, /\.quick-pane-send[\s\S]*?position: absolute/);
|
||||
assert.match(stylesheet, /@media \(max-width: 400px\)/);
|
||||
assert.match(stylesheet, /\.quick-pane\s*\{[\s\S]*?overflow: visible/);
|
||||
assert.match(stylesheet, /html,[\s\S]*?#root\s*\{[\s\S]*?overflow: hidden/);
|
||||
assert.match(stylesheet, /\.quick-pane\s*\{[\s\S]*?overflow: hidden/);
|
||||
assert.doesNotMatch(
|
||||
stylesheet,
|
||||
/\.quick-pane-primary-controls\s*\{[^}]*overflow:\s*(?:hidden|clip)/,
|
||||
@@ -227,4 +281,12 @@ test("Quick Pane uses native dimensions and request-first compact layout", async
|
||||
selectorStylesheet,
|
||||
/\.model-trigger\s*>\s*span\s*\{[\s\S]*?overflow:\s*hidden;[\s\S]*?text-overflow:\s*ellipsis/,
|
||||
);
|
||||
assert.match(
|
||||
selectorStylesheet,
|
||||
/\.model-menu\s*\{[\s\S]*?grid-template-rows:\s*auto auto minmax\(0, 1fr\);[\s\S]*?overflow:\s*hidden/,
|
||||
);
|
||||
assert.match(
|
||||
selectorStylesheet,
|
||||
/\.model-results\s*\{[\s\S]*?overflow-y:\s*auto/,
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user