pi-studio-opencode 0.1.0 → 0.2.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/dist/host-opencode-plugin.js +2 -0
- package/dist/host-opencode-plugin.js.map +1 -1
- package/dist/host-opencode.d.ts +1 -0
- package/dist/host-opencode.js +9 -1
- package/dist/host-opencode.js.map +1 -1
- package/dist/host-pi.js +24 -1
- package/dist/host-pi.js.map +1 -1
- package/dist/prototype-critique.d.ts +6 -0
- package/dist/prototype-critique.js +116 -0
- package/dist/prototype-critique.js.map +1 -0
- package/dist/prototype-server.d.ts +9 -1
- package/dist/prototype-server.js +66 -9
- package/dist/prototype-server.js.map +1 -1
- package/dist/studio-core.d.ts +2 -0
- package/dist/studio-core.js +3 -0
- package/dist/studio-core.js.map +1 -1
- package/dist/studio-host-types.d.ts +1 -0
- package/dist/studio-host-types.js.map +1 -1
- package/package.json +1 -1
- package/static/prototype.css +11 -2
- package/static/prototype.html +9 -0
- package/static/prototype.js +380 -48
package/static/prototype.js
CHANGED
|
@@ -92,7 +92,11 @@ Object.keys(LANG_EXT_MAP).forEach((lang) => {
|
|
|
92
92
|
});
|
|
93
93
|
});
|
|
94
94
|
const HIGHLIGHTED_LANGUAGES = ["markdown", "javascript", "typescript", "python", "bash", "json", "rust", "c", "cpp", "julia", "fortran", "r", "matlab", "latex", "diff"];
|
|
95
|
-
const SUPPORTED_LANGUAGES = Object.keys(LANG_EXT_MAP)
|
|
95
|
+
const SUPPORTED_LANGUAGES = Object.keys(LANG_EXT_MAP).sort((a, b) => {
|
|
96
|
+
const labelA = String(LANG_EXT_MAP[a]?.label || a);
|
|
97
|
+
const labelB = String(LANG_EXT_MAP[b]?.label || b);
|
|
98
|
+
return labelA.localeCompare(labelB);
|
|
99
|
+
});
|
|
96
100
|
|
|
97
101
|
const elements = {
|
|
98
102
|
leftPane: document.getElementById("leftPane"),
|
|
@@ -116,6 +120,8 @@ const elements = {
|
|
|
116
120
|
annotationModeSelect: document.getElementById("annotationModeSelect"),
|
|
117
121
|
stripAnnotationsBtn: document.getElementById("stripAnnotationsBtn"),
|
|
118
122
|
saveAnnotatedBtn: document.getElementById("saveAnnotatedBtn"),
|
|
123
|
+
lensSelect: document.getElementById("lensSelect"),
|
|
124
|
+
critiqueBtn: document.getElementById("critiqueBtn"),
|
|
119
125
|
highlightSelect: document.getElementById("highlightSelect"),
|
|
120
126
|
langSelect: document.getElementById("langSelect"),
|
|
121
127
|
sourceHighlight: document.getElementById("sourceHighlight"),
|
|
@@ -134,6 +140,8 @@ const elements = {
|
|
|
134
140
|
historyLastBtn: document.getElementById("historyLastBtn"),
|
|
135
141
|
historyIndexBadge: document.getElementById("historyIndexBadge"),
|
|
136
142
|
loadResponseBtn: document.getElementById("loadResponseBtn"),
|
|
143
|
+
loadCritiqueNotesBtn: document.getElementById("loadCritiqueNotesBtn"),
|
|
144
|
+
loadCritiqueFullBtn: document.getElementById("loadCritiqueFullBtn"),
|
|
137
145
|
loadHistoryPromptBtn: document.getElementById("loadHistoryPromptBtn"),
|
|
138
146
|
copyResponseBtn: document.getElementById("copyResponseBtn"),
|
|
139
147
|
exportPdfBtn: document.getElementById("exportPdfBtn"),
|
|
@@ -505,7 +513,7 @@ function maybeArmCompletionTitleAttention(snapshot, { initial = false } = {}) {
|
|
|
505
513
|
|
|
506
514
|
state.lastCompletedTurnKey = nextKey;
|
|
507
515
|
if (!shouldShowTitleAttention()) return;
|
|
508
|
-
armTitleAttention("● Response ready");
|
|
516
|
+
armTitleAttention(getRequestKind(snapshot?.lastCompletedTurn) === "critique" ? "● Critique ready" : "● Response ready");
|
|
509
517
|
}
|
|
510
518
|
|
|
511
519
|
function applySnapshot(snapshot, options = {}) {
|
|
@@ -513,9 +521,75 @@ function applySnapshot(snapshot, options = {}) {
|
|
|
513
521
|
maybeArmCompletionTitleAttention(state.snapshot, options);
|
|
514
522
|
}
|
|
515
523
|
|
|
524
|
+
function getRequestKind(value) {
|
|
525
|
+
if (value && value.requestKind === "critique") return "critique";
|
|
526
|
+
if (value && value.promptMode === "response") return "response";
|
|
527
|
+
return "run";
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
function isCritiqueResponseMarkdown(markdown) {
|
|
531
|
+
const lower = String(markdown || "").toLowerCase();
|
|
532
|
+
return lower.includes("## critiques") && lower.includes("## document");
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function isCritiqueHistoryItem(item) {
|
|
536
|
+
return Boolean(item) && (getRequestKind(item) === "critique" || isCritiqueResponseMarkdown(item.responseText || ""));
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
function isCritiqueDisplay(display) {
|
|
540
|
+
if (!display) return false;
|
|
541
|
+
if (display.kind === "history") {
|
|
542
|
+
return isCritiqueHistoryItem(display.item);
|
|
543
|
+
}
|
|
544
|
+
if (display.kind === "active") {
|
|
545
|
+
return getRequestKind(display.turn) === "critique";
|
|
546
|
+
}
|
|
547
|
+
return false;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function extractMarkdownSection(markdown, title) {
|
|
551
|
+
const heading = `## ${String(title || "").trim().toLowerCase()}`;
|
|
552
|
+
const lines = String(markdown || "").split("\n");
|
|
553
|
+
let start = -1;
|
|
554
|
+
|
|
555
|
+
for (let i = 0; i < lines.length; i++) {
|
|
556
|
+
if (String(lines[i] || "").trim().toLowerCase() === heading) {
|
|
557
|
+
start = i + 1;
|
|
558
|
+
break;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
if (start < 0) return "";
|
|
563
|
+
|
|
564
|
+
const collected = [];
|
|
565
|
+
for (let i = start; i < lines.length; i++) {
|
|
566
|
+
const line = lines[i];
|
|
567
|
+
if (String(line || "").trim().startsWith("## ")) break;
|
|
568
|
+
collected.push(line);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
return collected.join("\n").trim();
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function buildCritiqueNotesMarkdown(markdown) {
|
|
575
|
+
const assessment = extractMarkdownSection(markdown, "Assessment");
|
|
576
|
+
const critiques = extractMarkdownSection(markdown, "Critiques");
|
|
577
|
+
const parts = [];
|
|
578
|
+
|
|
579
|
+
if (assessment) {
|
|
580
|
+
parts.push(`## Assessment\n\n${assessment}`);
|
|
581
|
+
}
|
|
582
|
+
if (critiques) {
|
|
583
|
+
parts.push(`## Critiques\n\n${critiques}`);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
return parts.join("\n\n").trim();
|
|
587
|
+
}
|
|
588
|
+
|
|
516
589
|
function getHistoryPromptButtonLabel(item) {
|
|
517
590
|
if (!item) return "Load response prompt into editor";
|
|
518
591
|
if (item.promptMode === "steer") return "Load effective prompt into editor";
|
|
592
|
+
if (item.promptMode === "run" && getRequestKind(item) === "critique") return "Load critique prompt into editor";
|
|
519
593
|
if (item.promptMode === "run") return "Load run prompt into editor";
|
|
520
594
|
return "Load response prompt into editor";
|
|
521
595
|
}
|
|
@@ -523,6 +597,7 @@ function getHistoryPromptButtonLabel(item) {
|
|
|
523
597
|
function getHistoryPromptLoadedStatus(item) {
|
|
524
598
|
if (!item) return "Prompt unavailable for the selected response.";
|
|
525
599
|
if (item.promptMode === "steer") return "Loaded effective prompt into editor.";
|
|
600
|
+
if (item.promptMode === "run" && getRequestKind(item) === "critique") return "Loaded critique prompt into editor.";
|
|
526
601
|
if (item.promptMode === "run") return "Loaded run prompt into editor.";
|
|
527
602
|
return "Loaded response prompt into editor.";
|
|
528
603
|
}
|
|
@@ -530,12 +605,14 @@ function getHistoryPromptLoadedStatus(item) {
|
|
|
530
605
|
function getHistoryPromptSourceStateLabel(item) {
|
|
531
606
|
if (!item) return "response prompt";
|
|
532
607
|
if (item.promptMode === "steer") return "effective prompt";
|
|
608
|
+
if (item.promptMode === "run" && getRequestKind(item) === "critique") return "critique prompt";
|
|
533
609
|
if (item.promptMode === "run") return "run prompt";
|
|
534
610
|
return "response prompt";
|
|
535
611
|
}
|
|
536
612
|
|
|
537
613
|
function getHistoryItemTitle(item) {
|
|
538
614
|
if (!item) return "Response";
|
|
615
|
+
if (item.promptMode === "run" && getRequestKind(item) === "critique") return "Critique";
|
|
539
616
|
if (item.promptMode === "run") return "Run";
|
|
540
617
|
if (item.promptMode === "steer") return `Steer ${item.promptSteeringCount}`;
|
|
541
618
|
return "Response";
|
|
@@ -1751,13 +1828,16 @@ async function renderResponsePreviewNow() {
|
|
|
1751
1828
|
|
|
1752
1829
|
function formatPromptDescriptor(turn) {
|
|
1753
1830
|
if (!turn) return "-";
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1831
|
+
if (turn.promptMode === "run") {
|
|
1832
|
+
return getRequestKind(turn) === "critique"
|
|
1833
|
+
? `chain ${turn.chainIndex} · critique`
|
|
1834
|
+
: `chain ${turn.chainIndex} · run`;
|
|
1835
|
+
}
|
|
1836
|
+
return `chain ${turn.chainIndex} · steer ${turn.promptSteeringCount}`;
|
|
1757
1837
|
}
|
|
1758
1838
|
|
|
1759
1839
|
function buildResponseDisplayText(item) {
|
|
1760
|
-
if (!item) return "No response yet. Run editor text
|
|
1840
|
+
if (!item) return "No response yet. Run editor text or critique editor text.";
|
|
1761
1841
|
const responseText = String(item.responseText || "");
|
|
1762
1842
|
if (item.responseError) {
|
|
1763
1843
|
return responseText.trim()
|
|
@@ -1767,6 +1847,12 @@ function buildResponseDisplayText(item) {
|
|
|
1767
1847
|
return responseText.trim() ? responseText : "(empty response)";
|
|
1768
1848
|
}
|
|
1769
1849
|
|
|
1850
|
+
function buildThinkingDisplayText(item) {
|
|
1851
|
+
if (!item) return "No thinking available for this response.";
|
|
1852
|
+
const thinkingText = String(item.responseThinking || "");
|
|
1853
|
+
return thinkingText.trim() ? thinkingText : "No thinking available for this response.";
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1770
1856
|
function getActiveTurnMarkdown(turn) {
|
|
1771
1857
|
if (!turn) return "";
|
|
1772
1858
|
return String(turn.outputPreview || turn.responseText || "");
|
|
@@ -1780,19 +1866,44 @@ function getResponseReferenceLabel(display) {
|
|
|
1780
1866
|
const selectedLabel = total > 0 && selectedIndex >= 0 ? `${selectedIndex + 1}/${total}` : `0/${total}`;
|
|
1781
1867
|
const item = display.item;
|
|
1782
1868
|
const time = formatReferenceTime(item.completedAt ?? item.submittedAt ?? 0);
|
|
1869
|
+
const responseLabel = isCritiqueHistoryItem(item) ? "assistant critique" : "assistant response";
|
|
1783
1870
|
return time
|
|
1784
|
-
? `Response history ${selectedLabel} ·
|
|
1785
|
-
: `Response history ${selectedLabel} ·
|
|
1871
|
+
? `Response history ${selectedLabel} · ${responseLabel} · ${time}`
|
|
1872
|
+
: `Response history ${selectedLabel} · ${responseLabel}`;
|
|
1786
1873
|
}
|
|
1787
1874
|
if (display.kind === "active" && display.turn) {
|
|
1788
1875
|
const time = formatReferenceTime(display.turn.firstOutputTextAt ?? display.turn.firstAssistantMessageAt ?? display.turn.submittedAt ?? 0);
|
|
1876
|
+
const responseLabel = getRequestKind(display.turn) === "critique" ? "Assistant critique in progress" : "Assistant response in progress";
|
|
1789
1877
|
return time
|
|
1790
|
-
?
|
|
1791
|
-
:
|
|
1878
|
+
? `${responseLabel} · ${time}`
|
|
1879
|
+
: responseLabel;
|
|
1792
1880
|
}
|
|
1793
1881
|
return "Latest response: none";
|
|
1794
1882
|
}
|
|
1795
1883
|
|
|
1884
|
+
function getThinkingReferenceLabel(display) {
|
|
1885
|
+
if (!display) return "Thinking: none";
|
|
1886
|
+
if (display.kind === "history" && display.item) {
|
|
1887
|
+
const selectedIndex = getSelectedHistoryIndex();
|
|
1888
|
+
const total = getHistory().length;
|
|
1889
|
+
const selectedLabel = total > 0 && selectedIndex >= 0 ? `${selectedIndex + 1}/${total}` : `0/${total}`;
|
|
1890
|
+
const item = display.item;
|
|
1891
|
+
const hasThinking = Boolean(normalizedText(item.responseThinking || ""));
|
|
1892
|
+
const time = formatReferenceTime(item.completedAt ?? item.submittedAt ?? 0);
|
|
1893
|
+
const label = hasThinking ? "assistant thinking" : "assistant thinking unavailable";
|
|
1894
|
+
return time
|
|
1895
|
+
? `Response history ${selectedLabel} · ${label} · ${time}`
|
|
1896
|
+
: `Response history ${selectedLabel} · ${label}`;
|
|
1897
|
+
}
|
|
1898
|
+
if (display.kind === "active" && display.turn) {
|
|
1899
|
+
const time = formatReferenceTime(display.turn.firstAssistantMessageAt ?? display.turn.submittedAt ?? 0);
|
|
1900
|
+
return time
|
|
1901
|
+
? `Assistant thinking in progress · ${time}`
|
|
1902
|
+
: "Assistant thinking in progress";
|
|
1903
|
+
}
|
|
1904
|
+
return "Thinking: none";
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1796
1907
|
function getDisplayedResponse() {
|
|
1797
1908
|
const activeTurn = state.followLatest ? state.snapshot?.activeTurn : null;
|
|
1798
1909
|
const activeMarkdown = activeTurn ? getActiveTurnMarkdown(activeTurn) : "";
|
|
@@ -1825,7 +1936,9 @@ function getDisplayedResponse() {
|
|
|
1825
1936
|
if (activeTurn) {
|
|
1826
1937
|
return {
|
|
1827
1938
|
kind: "active",
|
|
1828
|
-
text:
|
|
1939
|
+
text: getRequestKind(activeTurn) === "critique"
|
|
1940
|
+
? "Waiting for the active critique to produce a response."
|
|
1941
|
+
: "Waiting for the active turn to produce a response.",
|
|
1829
1942
|
markdown: "",
|
|
1830
1943
|
hasContent: false,
|
|
1831
1944
|
turn: activeTurn,
|
|
@@ -1835,7 +1948,41 @@ function getDisplayedResponse() {
|
|
|
1835
1948
|
|
|
1836
1949
|
return {
|
|
1837
1950
|
kind: "empty",
|
|
1838
|
-
text: "No response yet. Run editor text
|
|
1951
|
+
text: "No response yet. Run editor text or critique editor text.",
|
|
1952
|
+
markdown: "",
|
|
1953
|
+
hasContent: false,
|
|
1954
|
+
previewWarning: "",
|
|
1955
|
+
};
|
|
1956
|
+
}
|
|
1957
|
+
|
|
1958
|
+
function getDisplayedThinking() {
|
|
1959
|
+
const responseDisplay = getDisplayedResponse();
|
|
1960
|
+
if (responseDisplay.kind === "history" && responseDisplay.item) {
|
|
1961
|
+
const thinking = String(responseDisplay.item.responseThinking || "");
|
|
1962
|
+
return {
|
|
1963
|
+
kind: "history",
|
|
1964
|
+
text: buildThinkingDisplayText(responseDisplay.item),
|
|
1965
|
+
markdown: thinking,
|
|
1966
|
+
hasContent: Boolean(normalizedText(thinking)),
|
|
1967
|
+
item: responseDisplay.item,
|
|
1968
|
+
previewWarning: "",
|
|
1969
|
+
};
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
if (responseDisplay.kind === "active" && responseDisplay.turn) {
|
|
1973
|
+
return {
|
|
1974
|
+
kind: "active",
|
|
1975
|
+
text: "Waiting for the active turn to finish before thinking becomes available.",
|
|
1976
|
+
markdown: "",
|
|
1977
|
+
hasContent: false,
|
|
1978
|
+
turn: responseDisplay.turn,
|
|
1979
|
+
previewWarning: "",
|
|
1980
|
+
};
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
return {
|
|
1984
|
+
kind: "empty",
|
|
1985
|
+
text: "No thinking available for this response.",
|
|
1839
1986
|
markdown: "",
|
|
1840
1987
|
hasContent: false,
|
|
1841
1988
|
previewWarning: "",
|
|
@@ -1876,6 +2023,8 @@ function formatTurnSummary(turn) {
|
|
|
1876
2023
|
const effectiveEnd = turn.completedAt || now;
|
|
1877
2024
|
return [
|
|
1878
2025
|
["Prompt", formatPromptDescriptor(turn)],
|
|
2026
|
+
["Request", getRequestKind(turn)],
|
|
2027
|
+
["Critique focus", turn.critiqueLens || "-"],
|
|
1879
2028
|
["Submitted", formatAbsoluteTime(turn.submittedAt)],
|
|
1880
2029
|
["To busy", formatRelativeDuration(turn.submittedAt, turn.backendBusyAt)],
|
|
1881
2030
|
["To first assistant", formatRelativeDuration(turn.submittedAt, turn.firstAssistantMessageAt)],
|
|
@@ -1940,6 +2089,8 @@ function renderSelectionPanel() {
|
|
|
1940
2089
|
metaBlock.append(metaHeading);
|
|
1941
2090
|
appendMetaRow(metaBlock, "chain", String(item.chainIndex));
|
|
1942
2091
|
appendMetaRow(metaBlock, "mode", item.promptMode);
|
|
2092
|
+
appendMetaRow(metaBlock, "request", getRequestKind(item));
|
|
2093
|
+
appendMetaRow(metaBlock, "critique focus", item.critiqueLens || "-");
|
|
1943
2094
|
appendMetaRow(metaBlock, "steering count", String(item.promptSteeringCount));
|
|
1944
2095
|
appendMetaRow(metaBlock, "queued while busy", item.queuedWhileBusy ? "yes" : "no");
|
|
1945
2096
|
appendMetaRow(metaBlock, "submitted", formatAbsoluteTime(item.submittedAt));
|
|
@@ -1954,6 +2105,7 @@ function renderSelectionPanel() {
|
|
|
1954
2105
|
buildDetailBlock("Prompt text", item.promptText),
|
|
1955
2106
|
buildDetailBlock("Effective prompt", item.effectivePrompt),
|
|
1956
2107
|
buildDetailBlock("Response text", buildResponseDisplayText(item)),
|
|
2108
|
+
buildDetailBlock("Thinking text", buildThinkingDisplayText(item)),
|
|
1957
2109
|
);
|
|
1958
2110
|
|
|
1959
2111
|
elements.selectionPanel.innerHTML = "";
|
|
@@ -2016,6 +2168,7 @@ function renderHistoryDiagnostics() {
|
|
|
2016
2168
|
badges.className = "badges";
|
|
2017
2169
|
for (const [text, className] of [
|
|
2018
2170
|
[item.promptMode, item.promptMode],
|
|
2171
|
+
[getRequestKind(item), getRequestKind(item) === "critique" ? "critique" : ""],
|
|
2019
2172
|
[`steers:${item.promptSteeringCount}`, ""],
|
|
2020
2173
|
[item.queuedWhileBusy ? "queued-busy" : "direct", ""],
|
|
2021
2174
|
[item.responseError ? "error" : "ok", item.responseError ? "error" : ""],
|
|
@@ -2068,7 +2221,8 @@ function renderDiagnostics() {
|
|
|
2068
2221
|
function renderResponsePane() {
|
|
2069
2222
|
const history = getHistory();
|
|
2070
2223
|
const selectedIndex = getSelectedHistoryIndex();
|
|
2071
|
-
const
|
|
2224
|
+
const responseDisplay = getDisplayedResponse();
|
|
2225
|
+
const display = state.rightView === "thinking" ? getDisplayedThinking() : responseDisplay;
|
|
2072
2226
|
updatePendingResponseScrollReset(display);
|
|
2073
2227
|
|
|
2074
2228
|
if (elements.rightViewSelect) {
|
|
@@ -2078,6 +2232,19 @@ function renderResponsePane() {
|
|
|
2078
2232
|
const selected = history.length && selectedIndex >= 0 ? selectedIndex + 1 : 0;
|
|
2079
2233
|
elements.historyIndexBadge.textContent = `History: ${selected}/${history.length}`;
|
|
2080
2234
|
|
|
2235
|
+
if (state.rightView === "thinking") {
|
|
2236
|
+
cancelScheduledResponsePreviewRender();
|
|
2237
|
+
finishPreviewRender(elements.responseView);
|
|
2238
|
+
state.responsePreviewRenderNonce += 1;
|
|
2239
|
+
const thinkingText = String(display.text || "");
|
|
2240
|
+
state.currentRenderedPreviewKey = `thinking\u0000${display.kind}\u0000${thinkingText}`;
|
|
2241
|
+
setResponseViewHtml(buildPlainMarkdownHtml(thinkingText));
|
|
2242
|
+
applyPendingResponseScrollReset();
|
|
2243
|
+
scheduleResponsePaneRepaintNudge();
|
|
2244
|
+
elements.referenceBadge.textContent = getThinkingReferenceLabel(display);
|
|
2245
|
+
return;
|
|
2246
|
+
}
|
|
2247
|
+
|
|
2081
2248
|
if (state.rightView === "markdown") {
|
|
2082
2249
|
cancelScheduledResponsePreviewRender();
|
|
2083
2250
|
finishPreviewRender(elements.responseView);
|
|
@@ -2113,7 +2280,7 @@ function renderEditorMeta() {
|
|
|
2113
2280
|
const snapshot = state.snapshot;
|
|
2114
2281
|
const history = getHistory();
|
|
2115
2282
|
const selectedIndex = getSelectedHistoryIndex();
|
|
2116
|
-
const display = getDisplayedResponse();
|
|
2283
|
+
const display = state.rightView === "thinking" ? getDisplayedThinking() : getDisplayedResponse();
|
|
2117
2284
|
const editorTextNormalized = normalizedText(elements.promptInput.value);
|
|
2118
2285
|
const displayedResponseNormalized = display?.hasContent ? normalizedText(display.markdown) : "";
|
|
2119
2286
|
const inSync = Boolean(displayedResponseNormalized) && editorTextNormalized === displayedResponseNormalized;
|
|
@@ -2132,6 +2299,7 @@ function renderEditorMeta() {
|
|
|
2132
2299
|
elements.historyCountBadge.textContent = `History: ${history.length && selectedIndex >= 0 ? selectedIndex + 1 : 0}/${history.length}`;
|
|
2133
2300
|
elements.syncBadge.hidden = !inSync;
|
|
2134
2301
|
elements.syncBadge.classList.toggle("sync", inSync);
|
|
2302
|
+
elements.syncBadge.textContent = state.rightView === "thinking" ? "In sync with thinking" : "In sync with response";
|
|
2135
2303
|
if (elements.annotationModeSelect) {
|
|
2136
2304
|
elements.annotationModeSelect.value = state.annotationsEnabled ? "on" : "off";
|
|
2137
2305
|
elements.annotationModeSelect.title = state.annotationsEnabled
|
|
@@ -2199,7 +2367,13 @@ function deriveStatus() {
|
|
|
2199
2367
|
return { message: "Studio: sending request to the attached session…", level: "", spinning: true };
|
|
2200
2368
|
}
|
|
2201
2369
|
if (snapshot.state.runState === "stopping") {
|
|
2202
|
-
return {
|
|
2370
|
+
return {
|
|
2371
|
+
message: getRequestKind(snapshot.activeTurn) === "critique"
|
|
2372
|
+
? "Studio: stopping current critique…"
|
|
2373
|
+
: "Studio: stopping current run…",
|
|
2374
|
+
level: "warning",
|
|
2375
|
+
spinning: true,
|
|
2376
|
+
};
|
|
2203
2377
|
}
|
|
2204
2378
|
if (snapshot.state.runState === "running") {
|
|
2205
2379
|
const activeTurn = snapshot.activeTurn;
|
|
@@ -2211,9 +2385,15 @@ function deriveStatus() {
|
|
|
2211
2385
|
let action = "Studio: waiting for queued steering";
|
|
2212
2386
|
if (activeTurn) {
|
|
2213
2387
|
if (activeTurn.promptMode === "run") {
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2388
|
+
if (getRequestKind(activeTurn) === "critique") {
|
|
2389
|
+
action = activeTurn.firstOutputTextAt
|
|
2390
|
+
? "Studio: generating critique"
|
|
2391
|
+
: "Studio: running critique";
|
|
2392
|
+
} else {
|
|
2393
|
+
action = activeTurn.firstOutputTextAt
|
|
2394
|
+
? "Studio: generating response"
|
|
2395
|
+
: "Studio: running editor text";
|
|
2396
|
+
}
|
|
2217
2397
|
} else {
|
|
2218
2398
|
action = activeTurn.firstOutputTextAt
|
|
2219
2399
|
? `Studio: generating steering ${activeTurn.promptSteeringCount}`
|
|
@@ -2241,8 +2421,9 @@ function deriveStatus() {
|
|
|
2241
2421
|
const selected = history.length && selectedIndex >= 0 ? selectedIndex + 1 : history.length;
|
|
2242
2422
|
const time = formatReferenceTime(latest.completedAt ?? latest.submittedAt ?? 0);
|
|
2243
2423
|
const suffix = time ? ` · ${time}` : "";
|
|
2424
|
+
const readyLabel = isCritiqueHistoryItem(latest) ? "critique" : "response";
|
|
2244
2425
|
return {
|
|
2245
|
-
message: `Ready ·
|
|
2426
|
+
message: `Ready · ${readyLabel} ${selected}/${history.length}${suffix}`,
|
|
2246
2427
|
level: "",
|
|
2247
2428
|
spinning: false,
|
|
2248
2429
|
};
|
|
@@ -2343,18 +2524,42 @@ function updateActionState() {
|
|
|
2343
2524
|
const snapshot = state.snapshot;
|
|
2344
2525
|
const hasPrompt = Boolean(normalizedText(elements.promptInput.value));
|
|
2345
2526
|
const runState = snapshot?.state?.runState ?? "idle";
|
|
2346
|
-
const
|
|
2527
|
+
const activeRequestKind = getRequestKind(snapshot?.activeTurn);
|
|
2528
|
+
const runIsStop = runState === "running" && activeRequestKind !== "critique";
|
|
2529
|
+
const critiqueIsStop = runState === "running" && activeRequestKind === "critique";
|
|
2530
|
+
const stoppingRun = runState === "stopping" && activeRequestKind !== "critique";
|
|
2531
|
+
const stoppingCritique = runState === "stopping" && activeRequestKind === "critique";
|
|
2347
2532
|
const selectedItem = getSelectedHistoryItem();
|
|
2348
|
-
const
|
|
2533
|
+
const responseDisplay = getDisplayedResponse();
|
|
2534
|
+
const displayed = state.rightView === "thinking" ? getDisplayedThinking() : responseDisplay;
|
|
2535
|
+
const displayedResponseText = displayed?.hasContent ? normalizedText(displayed.markdown) : "";
|
|
2349
2536
|
const history = getHistory();
|
|
2350
2537
|
const selectedIndex = getSelectedHistoryIndex();
|
|
2351
|
-
const
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2538
|
+
const normalizedEditor = normalizedText(elements.promptInput.value);
|
|
2539
|
+
const selectedResponseItem = responseDisplay.kind === "history" ? responseDisplay.item : null;
|
|
2540
|
+
const critiqueHistoryItem = selectedResponseItem && isCritiqueHistoryItem(selectedResponseItem)
|
|
2541
|
+
? selectedResponseItem
|
|
2542
|
+
: null;
|
|
2543
|
+
const structuredCritiqueItem = critiqueHistoryItem && isCritiqueResponseMarkdown(critiqueHistoryItem.responseText || "")
|
|
2544
|
+
? critiqueHistoryItem
|
|
2545
|
+
: null;
|
|
2546
|
+
const critiqueNotes = structuredCritiqueItem ? buildCritiqueNotesMarkdown(structuredCritiqueItem.responseText || "") : "";
|
|
2547
|
+
const fullCritiqueText = structuredCritiqueItem ? String(structuredCritiqueItem.responseText || "") : "";
|
|
2548
|
+
const responseLoaded = Boolean(displayedResponseText) && normalizedEditor === displayedResponseText;
|
|
2549
|
+
const critiqueNotesLoaded = Boolean(critiqueNotes) && normalizedEditor === normalizedText(critiqueNotes);
|
|
2550
|
+
const fullCritiqueLoaded = Boolean(fullCritiqueText) && normalizedEditor === normalizedText(fullCritiqueText);
|
|
2551
|
+
|
|
2552
|
+
elements.runBtn.textContent = stoppingRun ? "Stopping…" : (runIsStop ? "Stop" : "Run editor text");
|
|
2553
|
+
elements.runBtn.classList.toggle("request-stop-active", runIsStop || stoppingRun);
|
|
2554
|
+
elements.runBtn.disabled = !snapshot || state.busy || runState === "stopping" || (runState === "running" ? !runIsStop : !hasPrompt);
|
|
2555
|
+
|
|
2556
|
+
if (elements.critiqueBtn) {
|
|
2557
|
+
elements.critiqueBtn.textContent = stoppingCritique ? "Stopping…" : (critiqueIsStop ? "Stop" : "Critique editor text");
|
|
2558
|
+
elements.critiqueBtn.classList.toggle("request-stop-active", critiqueIsStop || stoppingCritique);
|
|
2559
|
+
elements.critiqueBtn.disabled = !snapshot || state.busy || runState === "stopping" || (runState === "running" ? !critiqueIsStop : !hasPrompt);
|
|
2560
|
+
}
|
|
2561
|
+
|
|
2562
|
+
elements.queueBtn.disabled = !snapshot || state.busy || runState !== "running" || activeRequestKind === "critique" || !hasPrompt;
|
|
2358
2563
|
elements.copyDraftBtn.disabled = !hasPrompt;
|
|
2359
2564
|
if (elements.saveAsBtn) elements.saveAsBtn.disabled = state.busy || !hasPrompt;
|
|
2360
2565
|
if (elements.saveBtn) elements.saveBtn.disabled = state.busy || !hasPrompt || !state.sourcePath;
|
|
@@ -2364,6 +2569,7 @@ function updateActionState() {
|
|
|
2364
2569
|
if (elements.annotationModeSelect) elements.annotationModeSelect.disabled = state.busy;
|
|
2365
2570
|
if (elements.stripAnnotationsBtn) elements.stripAnnotationsBtn.disabled = state.busy || !hasAnnotationMarkers(elements.promptInput.value);
|
|
2366
2571
|
if (elements.saveAnnotatedBtn) elements.saveAnnotatedBtn.disabled = state.busy || !hasPrompt;
|
|
2572
|
+
if (elements.lensSelect) elements.lensSelect.disabled = state.busy || runState !== "idle";
|
|
2367
2573
|
if (elements.highlightSelect) elements.highlightSelect.disabled = state.busy;
|
|
2368
2574
|
if (elements.langSelect) elements.langSelect.disabled = state.busy;
|
|
2369
2575
|
if (elements.responseHighlightSelect) {
|
|
@@ -2376,8 +2582,44 @@ function updateActionState() {
|
|
|
2376
2582
|
elements.historyNextBtn.disabled = history.length === 0 || state.followLatest || selectedIndex < 0 || selectedIndex >= history.length - 1;
|
|
2377
2583
|
elements.historyLastBtn.disabled = history.length === 0 || (state.followLatest && selectedIndex === history.length - 1);
|
|
2378
2584
|
|
|
2379
|
-
|
|
2380
|
-
|
|
2585
|
+
if (state.rightView === "thinking") {
|
|
2586
|
+
elements.loadResponseBtn.hidden = false;
|
|
2587
|
+
if (elements.loadCritiqueNotesBtn) elements.loadCritiqueNotesBtn.hidden = true;
|
|
2588
|
+
if (elements.loadCritiqueFullBtn) elements.loadCritiqueFullBtn.hidden = true;
|
|
2589
|
+
|
|
2590
|
+
elements.loadResponseBtn.disabled = state.busy || !displayedResponseText || responseLoaded;
|
|
2591
|
+
elements.loadResponseBtn.textContent = !displayedResponseText
|
|
2592
|
+
? "Thinking unavailable"
|
|
2593
|
+
: (responseLoaded ? "Thinking already in editor" : "Load thinking into editor");
|
|
2594
|
+
|
|
2595
|
+
elements.copyResponseBtn.disabled = !displayedResponseText;
|
|
2596
|
+
elements.copyResponseBtn.textContent = "Copy thinking text";
|
|
2597
|
+
} else {
|
|
2598
|
+
const isStructuredCritique = Boolean(structuredCritiqueItem);
|
|
2599
|
+
elements.loadResponseBtn.hidden = isStructuredCritique;
|
|
2600
|
+
if (elements.loadCritiqueNotesBtn) elements.loadCritiqueNotesBtn.hidden = !isStructuredCritique;
|
|
2601
|
+
if (elements.loadCritiqueFullBtn) elements.loadCritiqueFullBtn.hidden = !isStructuredCritique;
|
|
2602
|
+
|
|
2603
|
+
elements.loadResponseBtn.disabled = state.busy || !displayedResponseText || responseLoaded || isStructuredCritique;
|
|
2604
|
+
elements.loadResponseBtn.textContent = responseLoaded ? "Response already in editor" : "Load response into editor";
|
|
2605
|
+
|
|
2606
|
+
if (elements.loadCritiqueNotesBtn) {
|
|
2607
|
+
elements.loadCritiqueNotesBtn.disabled = state.busy || !isStructuredCritique || !critiqueNotes || critiqueNotesLoaded;
|
|
2608
|
+
elements.loadCritiqueNotesBtn.textContent = critiqueNotesLoaded
|
|
2609
|
+
? "Critique notes already in editor"
|
|
2610
|
+
: "Load critique notes into editor";
|
|
2611
|
+
}
|
|
2612
|
+
if (elements.loadCritiqueFullBtn) {
|
|
2613
|
+
elements.loadCritiqueFullBtn.disabled = state.busy || !isStructuredCritique || fullCritiqueLoaded;
|
|
2614
|
+
elements.loadCritiqueFullBtn.textContent = fullCritiqueLoaded
|
|
2615
|
+
? "Full critique already in editor"
|
|
2616
|
+
: "Load full critique into editor";
|
|
2617
|
+
}
|
|
2618
|
+
|
|
2619
|
+
elements.copyResponseBtn.disabled = !displayedResponseText;
|
|
2620
|
+
elements.copyResponseBtn.textContent = critiqueHistoryItem ? "Copy critique text" : "Copy response text";
|
|
2621
|
+
}
|
|
2622
|
+
|
|
2381
2623
|
if (!selectedItem) {
|
|
2382
2624
|
elements.loadHistoryPromptBtn.disabled = true;
|
|
2383
2625
|
elements.loadHistoryPromptBtn.textContent = getHistoryPromptButtonLabel(null);
|
|
@@ -2387,13 +2629,13 @@ function updateActionState() {
|
|
|
2387
2629
|
elements.loadHistoryPromptBtn.textContent = getHistoryPromptButtonLabel(selectedItem);
|
|
2388
2630
|
}
|
|
2389
2631
|
|
|
2390
|
-
elements.copyResponseBtn.disabled = !displayedResponseText;
|
|
2391
|
-
|
|
2392
2632
|
if (elements.exportPdfBtn) {
|
|
2393
2633
|
const exportSource = getPdfExportSource();
|
|
2394
2634
|
const canExportPdf = Boolean(exportSource && normalizedText(exportSource.markdown));
|
|
2395
2635
|
elements.exportPdfBtn.disabled = state.pdfExportInProgress || !canExportPdf;
|
|
2396
|
-
if (state.rightView === "
|
|
2636
|
+
if (state.rightView === "thinking") {
|
|
2637
|
+
elements.exportPdfBtn.title = "Thinking view does not support PDF export yet.";
|
|
2638
|
+
} else if (state.rightView === "markdown") {
|
|
2397
2639
|
elements.exportPdfBtn.title = "Switch right pane to Response (Preview) or Editor (Preview) to export PDF.";
|
|
2398
2640
|
} else if (!canExportPdf) {
|
|
2399
2641
|
elements.exportPdfBtn.title = "Nothing to export yet.";
|
|
@@ -2781,16 +3023,23 @@ async function copyText(text, successMessage) {
|
|
|
2781
3023
|
setTransientStatus(successMessage, "success");
|
|
2782
3024
|
}
|
|
2783
3025
|
|
|
3026
|
+
async function requestStopActiveRun(requestKind = getRequestKind(state.snapshot?.activeTurn)) {
|
|
3027
|
+
try {
|
|
3028
|
+
await postJson("/api/stop");
|
|
3029
|
+
setTransientStatus(requestKind === "critique" ? "Stop requested for critique." : "Stop requested.", "success");
|
|
3030
|
+
} catch (error) {
|
|
3031
|
+
setTransientStatus(error instanceof Error ? error.message : String(error), "error");
|
|
3032
|
+
}
|
|
3033
|
+
}
|
|
3034
|
+
|
|
2784
3035
|
async function runOrStop() {
|
|
2785
3036
|
const snapshot = state.snapshot;
|
|
2786
3037
|
if (!snapshot) return;
|
|
2787
3038
|
if (snapshot.state.runState === "running") {
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
setTransientStatus("Stop requested.", "success");
|
|
2791
|
-
} catch (error) {
|
|
2792
|
-
setTransientStatus(error instanceof Error ? error.message : String(error), "error");
|
|
3039
|
+
if (getRequestKind(snapshot.activeTurn) === "critique") {
|
|
3040
|
+
return;
|
|
2793
3041
|
}
|
|
3042
|
+
await requestStopActiveRun("run");
|
|
2794
3043
|
return;
|
|
2795
3044
|
}
|
|
2796
3045
|
|
|
@@ -2809,6 +3058,37 @@ async function runOrStop() {
|
|
|
2809
3058
|
}
|
|
2810
3059
|
}
|
|
2811
3060
|
|
|
3061
|
+
async function critiqueOrStop() {
|
|
3062
|
+
const snapshot = state.snapshot;
|
|
3063
|
+
if (!snapshot) return;
|
|
3064
|
+
if (snapshot.state.runState === "running") {
|
|
3065
|
+
if (getRequestKind(snapshot.activeTurn) !== "critique") {
|
|
3066
|
+
return;
|
|
3067
|
+
}
|
|
3068
|
+
await requestStopActiveRun("critique");
|
|
3069
|
+
return;
|
|
3070
|
+
}
|
|
3071
|
+
|
|
3072
|
+
const document = normalizedText(prepareEditorTextForSend(elements.promptInput.value));
|
|
3073
|
+
if (!document) {
|
|
3074
|
+
setTransientStatus("Add editor text before critique.", "warning");
|
|
3075
|
+
return;
|
|
3076
|
+
}
|
|
3077
|
+
|
|
3078
|
+
const lens = elements.lensSelect && ["auto", "writing", "code"].includes(elements.lensSelect.value)
|
|
3079
|
+
? elements.lensSelect.value
|
|
3080
|
+
: "auto";
|
|
3081
|
+
|
|
3082
|
+
clearTitleAttention();
|
|
3083
|
+
try {
|
|
3084
|
+
const result = await postJson("/api/critique", { document, lens });
|
|
3085
|
+
const resolvedLens = ["writing", "code"].includes(result?.lens) ? result.lens : lens;
|
|
3086
|
+
setTransientStatus(`Running critique${resolvedLens === "auto" ? "" : ` (${resolvedLens})`}.`, "success");
|
|
3087
|
+
} catch (error) {
|
|
3088
|
+
setTransientStatus(error instanceof Error ? error.message : String(error), "error");
|
|
3089
|
+
}
|
|
3090
|
+
}
|
|
3091
|
+
|
|
2812
3092
|
async function queueSteering() {
|
|
2813
3093
|
const prompt = normalizedText(prepareEditorTextForSend(elements.promptInput.value));
|
|
2814
3094
|
if (!prompt) {
|
|
@@ -2876,15 +3156,45 @@ function handleHistoryLast() {
|
|
|
2876
3156
|
}
|
|
2877
3157
|
|
|
2878
3158
|
function loadSelectedResponse() {
|
|
2879
|
-
const display = getDisplayedResponse();
|
|
3159
|
+
const display = state.rightView === "thinking" ? getDisplayedThinking() : getDisplayedResponse();
|
|
2880
3160
|
const responseText = display?.hasContent ? String(display.markdown || "") : "";
|
|
2881
3161
|
if (!normalizedText(responseText)) {
|
|
2882
|
-
setTransientStatus("No response available yet.", "warning");
|
|
3162
|
+
setTransientStatus(state.rightView === "thinking" ? "No thinking available for the selected response." : "No response available yet.", "warning");
|
|
2883
3163
|
return;
|
|
2884
3164
|
}
|
|
2885
|
-
const originLabel =
|
|
3165
|
+
const originLabel = state.rightView === "thinking"
|
|
3166
|
+
? "assistant thinking"
|
|
3167
|
+
: (display.kind === "active" ? "live response" : "selected response");
|
|
2886
3168
|
setEditorText(responseText, originLabel, { sourcePath: null });
|
|
2887
|
-
setTransientStatus("Loaded response into editor.", "success");
|
|
3169
|
+
setTransientStatus(state.rightView === "thinking" ? "Loaded thinking into editor." : "Loaded response into editor.", "success");
|
|
3170
|
+
}
|
|
3171
|
+
|
|
3172
|
+
function loadSelectedCritiqueNotes() {
|
|
3173
|
+
const display = getDisplayedResponse();
|
|
3174
|
+
const item = display.kind === "history" ? display.item : null;
|
|
3175
|
+
if (!item || !isCritiqueHistoryItem(item) || !isCritiqueResponseMarkdown(item.responseText || "")) {
|
|
3176
|
+
setTransientStatus("The selected response is not a structured critique.", "warning");
|
|
3177
|
+
return;
|
|
3178
|
+
}
|
|
3179
|
+
const notes = buildCritiqueNotesMarkdown(item.responseText || "");
|
|
3180
|
+
if (!notes) {
|
|
3181
|
+
setTransientStatus("No critique notes (Assessment/Critiques) found in the selected response.", "warning");
|
|
3182
|
+
return;
|
|
3183
|
+
}
|
|
3184
|
+
setEditorText(notes, "critique notes", { sourcePath: null });
|
|
3185
|
+
setTransientStatus("Loaded critique notes into editor.", "success");
|
|
3186
|
+
}
|
|
3187
|
+
|
|
3188
|
+
function loadSelectedCritiqueFull() {
|
|
3189
|
+
const display = getDisplayedResponse();
|
|
3190
|
+
const item = display.kind === "history" ? display.item : null;
|
|
3191
|
+
const fullCritique = String(item?.responseText || "");
|
|
3192
|
+
if (!item || !isCritiqueHistoryItem(item) || !isCritiqueResponseMarkdown(fullCritique)) {
|
|
3193
|
+
setTransientStatus("The selected response is not a structured critique.", "warning");
|
|
3194
|
+
return;
|
|
3195
|
+
}
|
|
3196
|
+
setEditorText(fullCritique, "full critique", { sourcePath: null });
|
|
3197
|
+
setTransientStatus("Loaded full critique into editor.", "success");
|
|
2888
3198
|
}
|
|
2889
3199
|
|
|
2890
3200
|
function loadSelectedPrompt() {
|
|
@@ -2903,14 +3213,21 @@ function loadSelectedPrompt() {
|
|
|
2903
3213
|
}
|
|
2904
3214
|
|
|
2905
3215
|
async function copySelectedResponse() {
|
|
2906
|
-
const display = getDisplayedResponse();
|
|
3216
|
+
const display = state.rightView === "thinking" ? getDisplayedThinking() : getDisplayedResponse();
|
|
2907
3217
|
const responseText = display?.hasContent ? String(display.markdown || "") : "";
|
|
2908
3218
|
if (!normalizedText(responseText)) {
|
|
2909
|
-
setTransientStatus("No response available yet.", "warning");
|
|
3219
|
+
setTransientStatus(state.rightView === "thinking" ? "No thinking available yet." : "No response available yet.", "warning");
|
|
2910
3220
|
return;
|
|
2911
3221
|
}
|
|
2912
3222
|
try {
|
|
2913
|
-
await copyText(
|
|
3223
|
+
await copyText(
|
|
3224
|
+
responseText,
|
|
3225
|
+
state.rightView === "thinking"
|
|
3226
|
+
? "Copied thinking text."
|
|
3227
|
+
: (display.kind === "active"
|
|
3228
|
+
? (getRequestKind(display.turn) === "critique" ? "Copied live critique preview." : "Copied live response preview.")
|
|
3229
|
+
: (isCritiqueDisplay(display) ? "Copied critique text." : "Copied response text.")),
|
|
3230
|
+
);
|
|
2914
3231
|
} catch (error) {
|
|
2915
3232
|
setTransientStatus(error instanceof Error ? error.message : String(error), "error");
|
|
2916
3233
|
}
|
|
@@ -3033,9 +3350,13 @@ function handleGlobalShortcuts(event) {
|
|
|
3033
3350
|
return;
|
|
3034
3351
|
}
|
|
3035
3352
|
|
|
3036
|
-
if (plainEscape && state.snapshot?.state?.runState === "running"
|
|
3353
|
+
if (plainEscape && state.snapshot?.state?.runState === "running") {
|
|
3037
3354
|
event.preventDefault();
|
|
3038
|
-
|
|
3355
|
+
if (getRequestKind(state.snapshot?.activeTurn) === "critique") {
|
|
3356
|
+
void requestStopActiveRun("critique");
|
|
3357
|
+
} else {
|
|
3358
|
+
void requestStopActiveRun("run");
|
|
3359
|
+
}
|
|
3039
3360
|
return;
|
|
3040
3361
|
}
|
|
3041
3362
|
|
|
@@ -3085,6 +3406,9 @@ function wireEvents() {
|
|
|
3085
3406
|
|
|
3086
3407
|
elements.diagnosticsBtn.addEventListener("click", () => toggleDiagnostics());
|
|
3087
3408
|
elements.runBtn.addEventListener("click", () => void runOrStop());
|
|
3409
|
+
if (elements.critiqueBtn) {
|
|
3410
|
+
elements.critiqueBtn.addEventListener("click", () => void critiqueOrStop());
|
|
3411
|
+
}
|
|
3088
3412
|
elements.queueBtn.addEventListener("click", () => void queueSteering());
|
|
3089
3413
|
elements.copyDraftBtn.addEventListener("click", () => {
|
|
3090
3414
|
void copyText(elements.promptInput.value, "Copied editor text.").catch((error) => {
|
|
@@ -3114,7 +3438,9 @@ function wireEvents() {
|
|
|
3114
3438
|
elements.rightViewSelect.addEventListener("change", () => {
|
|
3115
3439
|
state.rightView = elements.rightViewSelect.value === "editor-preview"
|
|
3116
3440
|
? "editor-preview"
|
|
3117
|
-
: (elements.rightViewSelect.value === "markdown"
|
|
3441
|
+
: (elements.rightViewSelect.value === "markdown"
|
|
3442
|
+
? "markdown"
|
|
3443
|
+
: (elements.rightViewSelect.value === "thinking" ? "thinking" : "preview"));
|
|
3118
3444
|
state.currentRenderedPreviewKey = "";
|
|
3119
3445
|
render();
|
|
3120
3446
|
});
|
|
@@ -3149,6 +3475,12 @@ function wireEvents() {
|
|
|
3149
3475
|
elements.historyNextBtn.addEventListener("click", () => handleHistoryNext());
|
|
3150
3476
|
elements.historyLastBtn.addEventListener("click", () => handleHistoryLast());
|
|
3151
3477
|
elements.loadResponseBtn.addEventListener("click", () => loadSelectedResponse());
|
|
3478
|
+
if (elements.loadCritiqueNotesBtn) {
|
|
3479
|
+
elements.loadCritiqueNotesBtn.addEventListener("click", () => loadSelectedCritiqueNotes());
|
|
3480
|
+
}
|
|
3481
|
+
if (elements.loadCritiqueFullBtn) {
|
|
3482
|
+
elements.loadCritiqueFullBtn.addEventListener("click", () => loadSelectedCritiqueFull());
|
|
3483
|
+
}
|
|
3152
3484
|
elements.loadHistoryPromptBtn.addEventListener("click", () => loadSelectedPrompt());
|
|
3153
3485
|
elements.copyResponseBtn.addEventListener("click", () => void copySelectedResponse());
|
|
3154
3486
|
if (elements.exportPdfBtn) {
|