pi-studio 0.5.28 → 0.5.30
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 +13 -0
- package/client/studio-client.js +240 -45
- package/client/studio.css +10 -3
- package/index.ts +515 -39
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ All notable changes to `pi-studio` are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.5.30] — 2026-03-24
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- LaTeX preview now preserves structured display-math environments such as `bmatrix` inside `\[ ... \]` instead of flattening their rows during Markdown math normalization, and preview display equations now center more robustly across browser engines.
|
|
11
|
+
- Studio now highlights custom `[an: ...]` markers in LaTeX editor syntax-highlighting mode, and PDF export renders those markers as styled annotation badges for both Markdown and LaTeX documents instead of leaving the raw bracket syntax in the final PDF.
|
|
12
|
+
- Right-pane response PDF export now also respects the current annotation-visibility mode, so hidden annotations do not leak into exported PDFs as raw `[an: ...]` text.
|
|
13
|
+
|
|
14
|
+
## [0.5.29] — 2026-03-21
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- Studio keyboard shortcuts now keep `Cmd/Ctrl+Enter` for running editor text while using `Esc` to stop an active request, and the focus-pane hint/button copy now describes focus mode as a toggle via `F10` or `Cmd/Ctrl+Esc`.
|
|
18
|
+
- While **Run editor text** is active, Studio now exposes a separate **Queue steering** action (and `Cmd/Ctrl+Enter` queues steering) while preserving a visible **Stop** control, and response-history prompt loading now preserves the effective prompt chain for steered responses rather than only the last correction message.
|
|
19
|
+
|
|
7
20
|
## [0.5.28] — 2026-03-21
|
|
8
21
|
|
|
9
22
|
### Changed
|
package/client/studio-client.js
CHANGED
|
@@ -78,6 +78,7 @@
|
|
|
78
78
|
const getEditorBtn = document.getElementById("getEditorBtn");
|
|
79
79
|
const loadGitDiffBtn = document.getElementById("loadGitDiffBtn");
|
|
80
80
|
const sendRunBtn = document.getElementById("sendRunBtn");
|
|
81
|
+
const queueSteerBtn = document.getElementById("queueSteerBtn");
|
|
81
82
|
const copyDraftBtn = document.getElementById("copyDraftBtn");
|
|
82
83
|
const saveAnnotatedBtn = document.getElementById("saveAnnotatedBtn");
|
|
83
84
|
const stripAnnotationsBtn = document.getElementById("stripAnnotationsBtn");
|
|
@@ -120,6 +121,8 @@
|
|
|
120
121
|
let latestCritiqueNotesNormalized = "";
|
|
121
122
|
let responseHistory = [];
|
|
122
123
|
let responseHistoryIndex = -1;
|
|
124
|
+
let studioRunChainActive = false;
|
|
125
|
+
let queuedSteeringCount = 0;
|
|
123
126
|
let agentBusyFromServer = false;
|
|
124
127
|
let terminalActivityPhase = "idle";
|
|
125
128
|
let terminalActivityToolName = "";
|
|
@@ -152,6 +155,23 @@
|
|
|
152
155
|
return trimmed ? trimmed : null;
|
|
153
156
|
}
|
|
154
157
|
|
|
158
|
+
function applyStudioRunQueueStateFromMessage(message) {
|
|
159
|
+
if (!message || typeof message !== "object") return false;
|
|
160
|
+
let changed = false;
|
|
161
|
+
if (typeof message.studioRunChainActive === "boolean" && studioRunChainActive !== message.studioRunChainActive) {
|
|
162
|
+
studioRunChainActive = message.studioRunChainActive;
|
|
163
|
+
changed = true;
|
|
164
|
+
}
|
|
165
|
+
if (typeof message.queuedSteeringCount === "number" && Number.isFinite(message.queuedSteeringCount)) {
|
|
166
|
+
const nextCount = Math.max(0, Math.floor(message.queuedSteeringCount));
|
|
167
|
+
if (queuedSteeringCount !== nextCount) {
|
|
168
|
+
queuedSteeringCount = nextCount;
|
|
169
|
+
changed = true;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return changed;
|
|
173
|
+
}
|
|
174
|
+
|
|
155
175
|
contextTokens = parseFiniteNumber(document.body && document.body.dataset ? document.body.dataset.contextTokens : null);
|
|
156
176
|
contextWindow = parseFiniteNumber(document.body && document.body.dataset ? document.body.dataset.contextWindow : null);
|
|
157
177
|
contextPercent = parseFiniteNumber(document.body && document.body.dataset ? document.body.dataset.contextPercent : null);
|
|
@@ -383,26 +403,80 @@
|
|
|
383
403
|
return "submitting request";
|
|
384
404
|
}
|
|
385
405
|
|
|
406
|
+
function formatQueuedSteeringSuffix() {
|
|
407
|
+
if (!queuedSteeringCount) return "";
|
|
408
|
+
return queuedSteeringCount === 1
|
|
409
|
+
? " · 1 steering queued"
|
|
410
|
+
: " · " + queuedSteeringCount + " steering queued";
|
|
411
|
+
}
|
|
412
|
+
|
|
386
413
|
function getStudioBusyStatus(kind) {
|
|
387
414
|
const action = getStudioActionLabel(kind);
|
|
415
|
+
const queueSuffix = studioRunChainActive ? formatQueuedSteeringSuffix() : "";
|
|
388
416
|
if (terminalActivityPhase === "tool") {
|
|
389
417
|
if (terminalActivityLabel) {
|
|
390
|
-
return "Studio: " + withEllipsis(terminalActivityLabel);
|
|
418
|
+
return "Studio: " + withEllipsis(terminalActivityLabel) + queueSuffix;
|
|
391
419
|
}
|
|
392
420
|
return terminalActivityToolName
|
|
393
|
-
? "Studio: " + action + " (tool: " + terminalActivityToolName + ")…"
|
|
394
|
-
: "Studio: " + action + " (running tool)…";
|
|
421
|
+
? "Studio: " + action + " (tool: " + terminalActivityToolName + ")…" + queueSuffix
|
|
422
|
+
: "Studio: " + action + " (running tool)…" + queueSuffix;
|
|
395
423
|
}
|
|
396
424
|
if (terminalActivityPhase === "responding") {
|
|
397
425
|
if (lastSpecificToolLabel) {
|
|
398
|
-
return "Studio: " + lastSpecificToolLabel + " (generating response)…";
|
|
426
|
+
return "Studio: " + lastSpecificToolLabel + " (generating response)…" + queueSuffix;
|
|
399
427
|
}
|
|
400
|
-
return "Studio: " + action + " (generating response)…";
|
|
428
|
+
return "Studio: " + action + " (generating response)…" + queueSuffix;
|
|
401
429
|
}
|
|
402
430
|
if (terminalActivityPhase === "running" && lastSpecificToolLabel) {
|
|
403
|
-
return "Studio: " + withEllipsis(lastSpecificToolLabel);
|
|
431
|
+
return "Studio: " + withEllipsis(lastSpecificToolLabel) + queueSuffix;
|
|
432
|
+
}
|
|
433
|
+
return "Studio: " + action + "…" + queueSuffix;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function getHistoryPromptSourceLabel(item) {
|
|
437
|
+
if (!item || !item.promptMode) return null;
|
|
438
|
+
const steeringCount = typeof item.promptSteeringCount === "number" && Number.isFinite(item.promptSteeringCount)
|
|
439
|
+
? Math.max(0, Math.floor(item.promptSteeringCount))
|
|
440
|
+
: 0;
|
|
441
|
+
if (item.promptMode === "run") return "original run";
|
|
442
|
+
if (item.promptMode !== "effective") return null;
|
|
443
|
+
if (steeringCount <= 0) return "original run";
|
|
444
|
+
return steeringCount === 1
|
|
445
|
+
? "original run + 1 steering message"
|
|
446
|
+
: "original run + " + steeringCount + " steering messages";
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function getHistoryPromptButtonLabel(item) {
|
|
450
|
+
if (!item || !item.prompt || !String(item.prompt).trim()) {
|
|
451
|
+
return "Response prompt unavailable";
|
|
452
|
+
}
|
|
453
|
+
if (item.promptMode === "effective") {
|
|
454
|
+
return "Load effective prompt into editor";
|
|
455
|
+
}
|
|
456
|
+
if (item.promptMode === "run") {
|
|
457
|
+
return "Load run prompt into editor";
|
|
458
|
+
}
|
|
459
|
+
return "Load response prompt into editor";
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
function getHistoryPromptLoadedStatus(item) {
|
|
463
|
+
if (!item || !item.prompt || !String(item.prompt).trim()) {
|
|
464
|
+
return "Prompt unavailable for the selected response.";
|
|
465
|
+
}
|
|
466
|
+
if (item.promptMode === "effective") {
|
|
467
|
+
return "Loaded effective prompt into editor.";
|
|
468
|
+
}
|
|
469
|
+
if (item.promptMode === "run") {
|
|
470
|
+
return "Loaded run prompt into editor.";
|
|
404
471
|
}
|
|
405
|
-
return "
|
|
472
|
+
return "Loaded response prompt into editor.";
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function getHistoryPromptSourceStateLabel(item) {
|
|
476
|
+
if (!item || !item.prompt || !String(item.prompt).trim()) return "response prompt";
|
|
477
|
+
if (item.promptMode === "effective") return "effective prompt";
|
|
478
|
+
if (item.promptMode === "run") return "run prompt";
|
|
479
|
+
return "response prompt";
|
|
406
480
|
}
|
|
407
481
|
|
|
408
482
|
function shouldAnimateFooterSpinner() {
|
|
@@ -715,8 +789,8 @@
|
|
|
715
789
|
btn.setAttribute("aria-pressed", isFocusedPane ? "true" : "false");
|
|
716
790
|
btn.textContent = isFocusedPane ? "Exit focus" : "Focus pane";
|
|
717
791
|
btn.title = isFocusedPane
|
|
718
|
-
? "
|
|
719
|
-
: "Show only the " + paneName + " pane. Shortcut: Cmd/Ctrl+Esc
|
|
792
|
+
? "Return to the two-pane layout. Shortcut: F10 or Cmd/Ctrl+Esc."
|
|
793
|
+
: "Show only the " + paneName + " pane. Shortcut: F10 or Cmd/Ctrl+Esc.";
|
|
720
794
|
});
|
|
721
795
|
}
|
|
722
796
|
|
|
@@ -754,7 +828,7 @@
|
|
|
754
828
|
setActivePane(pane);
|
|
755
829
|
paneFocusTarget = pane;
|
|
756
830
|
applyPaneFocusClasses();
|
|
757
|
-
setStatus("Focus mode: " + paneLabel(pane) + " pane
|
|
831
|
+
setStatus("Focus mode: " + paneLabel(pane) + " pane. Toggle with F10 or Cmd/Ctrl+Esc.");
|
|
758
832
|
}
|
|
759
833
|
|
|
760
834
|
function togglePaneFocus() {
|
|
@@ -777,7 +851,7 @@
|
|
|
777
851
|
}
|
|
778
852
|
|
|
779
853
|
function handlePaneShortcut(event) {
|
|
780
|
-
if (!event) return;
|
|
854
|
+
if (!event || event.defaultPrevented) return;
|
|
781
855
|
|
|
782
856
|
const key = typeof event.key === "string" ? event.key : "";
|
|
783
857
|
const isToggleShortcut =
|
|
@@ -797,9 +871,16 @@
|
|
|
797
871
|
&& !event.altKey
|
|
798
872
|
&& !event.shiftKey
|
|
799
873
|
) {
|
|
874
|
+
const activeKind = getAbortablePendingKind();
|
|
875
|
+
if (activeKind === "direct" || activeKind === "critique") {
|
|
876
|
+
event.preventDefault();
|
|
877
|
+
requestCancelForPendingRequest(activeKind);
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
800
880
|
if (exitPaneFocus()) {
|
|
801
881
|
event.preventDefault();
|
|
802
882
|
}
|
|
883
|
+
return;
|
|
803
884
|
}
|
|
804
885
|
|
|
805
886
|
if (
|
|
@@ -808,11 +889,16 @@
|
|
|
808
889
|
&& !event.altKey
|
|
809
890
|
&& !event.shiftKey
|
|
810
891
|
&& activePane === "left"
|
|
811
|
-
&& sendRunBtn
|
|
812
|
-
&& !sendRunBtn.disabled
|
|
813
892
|
) {
|
|
814
|
-
|
|
815
|
-
|
|
893
|
+
if (queueSteerBtn && !queueSteerBtn.disabled) {
|
|
894
|
+
event.preventDefault();
|
|
895
|
+
queueSteerBtn.click();
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
if (sendRunBtn && !sendRunBtn.disabled) {
|
|
899
|
+
event.preventDefault();
|
|
900
|
+
sendRunBtn.click();
|
|
901
|
+
}
|
|
816
902
|
}
|
|
817
903
|
}
|
|
818
904
|
|
|
@@ -851,6 +937,18 @@
|
|
|
851
937
|
const thinking = typeof item.thinking === "string"
|
|
852
938
|
? item.thinking
|
|
853
939
|
: (item.thinking == null ? null : String(item.thinking));
|
|
940
|
+
const promptMode = item.promptMode === "run" || item.promptMode === "effective"
|
|
941
|
+
? item.promptMode
|
|
942
|
+
: "response";
|
|
943
|
+
const promptTriggerKind = item.promptTriggerKind === "run" || item.promptTriggerKind === "steer"
|
|
944
|
+
? item.promptTriggerKind
|
|
945
|
+
: null;
|
|
946
|
+
const promptSteeringCount = typeof item.promptSteeringCount === "number" && Number.isFinite(item.promptSteeringCount)
|
|
947
|
+
? Math.max(0, Math.floor(item.promptSteeringCount))
|
|
948
|
+
: 0;
|
|
949
|
+
const promptTriggerText = typeof item.promptTriggerText === "string"
|
|
950
|
+
? item.promptTriggerText
|
|
951
|
+
: (item.promptTriggerText == null ? null : String(item.promptTriggerText));
|
|
854
952
|
|
|
855
953
|
return {
|
|
856
954
|
id,
|
|
@@ -859,6 +957,10 @@
|
|
|
859
957
|
timestamp,
|
|
860
958
|
kind: normalizeHistoryKind(item.kind),
|
|
861
959
|
prompt,
|
|
960
|
+
promptMode,
|
|
961
|
+
promptTriggerKind,
|
|
962
|
+
promptSteeringCount,
|
|
963
|
+
promptTriggerText,
|
|
862
964
|
};
|
|
863
965
|
}
|
|
864
966
|
|
|
@@ -904,9 +1006,13 @@
|
|
|
904
1006
|
const hasPrompt = Boolean(selectedItem && typeof selectedItem.prompt === "string" && selectedItem.prompt.trim());
|
|
905
1007
|
if (loadHistoryPromptBtn) {
|
|
906
1008
|
loadHistoryPromptBtn.disabled = uiBusy || !hasPrompt;
|
|
907
|
-
loadHistoryPromptBtn.textContent =
|
|
908
|
-
|
|
909
|
-
|
|
1009
|
+
loadHistoryPromptBtn.textContent = getHistoryPromptButtonLabel(selectedItem);
|
|
1010
|
+
const promptSourceLabel = getHistoryPromptSourceLabel(selectedItem);
|
|
1011
|
+
loadHistoryPromptBtn.title = hasPrompt
|
|
1012
|
+
? (promptSourceLabel
|
|
1013
|
+
? "Load the " + promptSourceLabel + " prompt chain that generated the selected response into the editor."
|
|
1014
|
+
: "Load the prompt that generated the selected response into the editor.")
|
|
1015
|
+
: "Prompt unavailable for the selected response.";
|
|
910
1016
|
}
|
|
911
1017
|
}
|
|
912
1018
|
|
|
@@ -1609,7 +1715,9 @@
|
|
|
1609
1715
|
return;
|
|
1610
1716
|
}
|
|
1611
1717
|
|
|
1612
|
-
const markdown = rightView === "editor-preview"
|
|
1718
|
+
const markdown = rightView === "editor-preview"
|
|
1719
|
+
? prepareEditorTextForPdfExport(sourceTextEl.value)
|
|
1720
|
+
: prepareEditorTextForPreview(latestResponseMarkdown);
|
|
1613
1721
|
if (!markdown || !markdown.trim()) {
|
|
1614
1722
|
setStatus("Nothing to export yet.", "warning");
|
|
1615
1723
|
return;
|
|
@@ -2452,17 +2560,49 @@
|
|
|
2452
2560
|
}
|
|
2453
2561
|
|
|
2454
2562
|
if (lang === "latex") {
|
|
2455
|
-
const texPattern = /(%.*$)|(\\(?:documentclass|usepackage|newtheorem|begin|end|section|subsection|subsubsection|chapter|part|title|author|date|maketitle|tableofcontents|includegraphics|caption|label|ref|eqref|cite|textbf|textit|texttt|emph|footnote|centering|newcommand|renewcommand|providecommand|bibliography|bibliographystyle|bibitem|item|input|include)\b)|(\\[A-Za-z]+)|(\{|\})|(\$\$?(?:[^$\\]|\\.)+\$\$?)|(\[(?:.*?)\])/
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2563
|
+
const texPattern = /(%.*$)|(\[an:\s*[^\]]+\])|(\\(?:documentclass|usepackage|newtheorem|begin|end|section|subsection|subsubsection|chapter|part|title|author|date|maketitle|tableofcontents|includegraphics|caption|label|ref|eqref|cite|textbf|textit|texttt|emph|footnote|centering|newcommand|renewcommand|providecommand|bibliography|bibliographystyle|bibitem|item|input|include)\b)|(\\[A-Za-z]+)|(\{|\})|(\$\$?(?:[^$\\]|\\.)+\$\$?)|(\[(?:.*?)\])/gi;
|
|
2564
|
+
let out = "";
|
|
2565
|
+
let lastIndex = 0;
|
|
2566
|
+
texPattern.lastIndex = 0;
|
|
2567
|
+
|
|
2568
|
+
let match;
|
|
2569
|
+
while ((match = texPattern.exec(source)) !== null) {
|
|
2570
|
+
const token = match[0] || "";
|
|
2571
|
+
const start = typeof match.index === "number" ? match.index : 0;
|
|
2572
|
+
|
|
2573
|
+
if (start > lastIndex) {
|
|
2574
|
+
out += escapeHtml(source.slice(lastIndex, start));
|
|
2575
|
+
}
|
|
2576
|
+
|
|
2577
|
+
if (match[1]) {
|
|
2578
|
+
out += wrapHighlight("hl-code-com", token);
|
|
2579
|
+
} else if (match[2]) {
|
|
2580
|
+
out += highlightInlineAnnotations(token, renderMode);
|
|
2581
|
+
} else if (match[3]) {
|
|
2582
|
+
out += wrapHighlight("hl-code-kw", token);
|
|
2583
|
+
} else if (match[4]) {
|
|
2584
|
+
out += wrapHighlight("hl-code-fn", token);
|
|
2585
|
+
} else if (match[5]) {
|
|
2586
|
+
out += wrapHighlight("hl-code-op", token);
|
|
2587
|
+
} else if (match[6]) {
|
|
2588
|
+
out += wrapHighlight("hl-code-str", token);
|
|
2589
|
+
} else if (match[7]) {
|
|
2590
|
+
out += wrapHighlight("hl-code-num", token);
|
|
2591
|
+
} else {
|
|
2592
|
+
out += escapeHtml(token);
|
|
2593
|
+
}
|
|
2594
|
+
|
|
2595
|
+
lastIndex = start + token.length;
|
|
2596
|
+
if (token.length === 0) {
|
|
2597
|
+
texPattern.lastIndex += 1;
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
|
|
2601
|
+
if (lastIndex < source.length) {
|
|
2602
|
+
out += escapeHtml(source.slice(lastIndex));
|
|
2603
|
+
}
|
|
2604
|
+
|
|
2605
|
+
return out;
|
|
2466
2606
|
}
|
|
2467
2607
|
|
|
2468
2608
|
if (lang === "diff") {
|
|
@@ -2806,29 +2946,43 @@
|
|
|
2806
2946
|
|
|
2807
2947
|
function syncRunAndCritiqueButtons() {
|
|
2808
2948
|
const activeKind = getAbortablePendingKind();
|
|
2809
|
-
const
|
|
2949
|
+
const directIsStop = activeKind === "direct";
|
|
2810
2950
|
const critiqueIsStop = activeKind === "critique";
|
|
2951
|
+
const canQueueSteering = studioRunChainActive && !critiqueIsStop;
|
|
2811
2952
|
|
|
2812
2953
|
if (sendRunBtn) {
|
|
2813
|
-
sendRunBtn.textContent =
|
|
2814
|
-
sendRunBtn.classList.toggle("request-stop-active",
|
|
2815
|
-
sendRunBtn.disabled =
|
|
2816
|
-
sendRunBtn.title =
|
|
2817
|
-
? "Stop the
|
|
2954
|
+
sendRunBtn.textContent = directIsStop ? "Stop" : "Run editor text";
|
|
2955
|
+
sendRunBtn.classList.toggle("request-stop-active", directIsStop);
|
|
2956
|
+
sendRunBtn.disabled = wsState === "Disconnected" || (!directIsStop && (uiBusy || critiqueIsStop));
|
|
2957
|
+
sendRunBtn.title = directIsStop
|
|
2958
|
+
? "Stop the active run. Shortcut: Esc."
|
|
2818
2959
|
: (annotationsEnabled
|
|
2819
|
-
? "Run editor text as-is (includes [an: ...] markers). Shortcut: Cmd/Ctrl+Enter."
|
|
2820
|
-
: "Run editor text with [an: ...] markers stripped. Shortcut: Cmd/Ctrl+Enter.");
|
|
2960
|
+
? "Run editor text as-is (includes [an: ...] markers). Shortcut: Cmd/Ctrl+Enter. Stop the active request with Esc."
|
|
2961
|
+
: "Run editor text with [an: ...] markers stripped. Shortcut: Cmd/Ctrl+Enter. Stop the active request with Esc.");
|
|
2962
|
+
}
|
|
2963
|
+
|
|
2964
|
+
if (queueSteerBtn) {
|
|
2965
|
+
queueSteerBtn.hidden = false;
|
|
2966
|
+
queueSteerBtn.disabled = wsState === "Disconnected" || !canQueueSteering;
|
|
2967
|
+
queueSteerBtn.classList.remove("request-stop-active");
|
|
2968
|
+
queueSteerBtn.title = canQueueSteering
|
|
2969
|
+
? (annotationsEnabled
|
|
2970
|
+
? "Queue the current editor text as a steering message for the active run. Shortcut: Cmd/Ctrl+Enter."
|
|
2971
|
+
: "Queue the current editor text as a steering message for the active run after stripping [an: ...] markers. Shortcut: Cmd/Ctrl+Enter.")
|
|
2972
|
+
: "Queue steering is available while Run editor text is active.";
|
|
2821
2973
|
}
|
|
2822
2974
|
|
|
2823
2975
|
if (critiqueBtn) {
|
|
2824
2976
|
critiqueBtn.textContent = critiqueIsStop ? "Stop" : "Critique editor text";
|
|
2825
2977
|
critiqueBtn.classList.toggle("request-stop-active", critiqueIsStop);
|
|
2826
|
-
critiqueBtn.disabled = critiqueIsStop ? wsState === "Disconnected" : (uiBusy ||
|
|
2978
|
+
critiqueBtn.disabled = critiqueIsStop ? wsState === "Disconnected" : (uiBusy || canQueueSteering);
|
|
2827
2979
|
critiqueBtn.title = critiqueIsStop
|
|
2828
|
-
? "Stop the running critique request."
|
|
2829
|
-
: (
|
|
2830
|
-
? "Critique editor text
|
|
2831
|
-
:
|
|
2980
|
+
? "Stop the running critique request. Shortcut: Esc."
|
|
2981
|
+
: (canQueueSteering
|
|
2982
|
+
? "Critique queueing is not supported while Run editor text is active."
|
|
2983
|
+
: (annotationsEnabled
|
|
2984
|
+
? "Critique editor text as-is (includes [an: ...] markers)."
|
|
2985
|
+
: "Critique editor text with [an: ...] markers stripped."));
|
|
2832
2986
|
}
|
|
2833
2987
|
}
|
|
2834
2988
|
|
|
@@ -2973,6 +3127,7 @@
|
|
|
2973
3127
|
if (typeof message.terminalSessionLabel === "string") {
|
|
2974
3128
|
terminalSessionLabel = message.terminalSessionLabel;
|
|
2975
3129
|
}
|
|
3130
|
+
applyStudioRunQueueStateFromMessage(message);
|
|
2976
3131
|
updateFooterMeta();
|
|
2977
3132
|
setBusy(busy);
|
|
2978
3133
|
setWsState(busy ? "Submitting" : "Ready");
|
|
@@ -3045,6 +3200,8 @@
|
|
|
3045
3200
|
if (busy) {
|
|
3046
3201
|
if (agentBusyFromServer && stickyStudioKind) {
|
|
3047
3202
|
setStatus(getStudioBusyStatus(stickyStudioKind), "warning");
|
|
3203
|
+
} else if (agentBusyFromServer && studioRunChainActive) {
|
|
3204
|
+
setStatus(getStudioBusyStatus("direct"), "warning");
|
|
3048
3205
|
} else if (agentBusyFromServer) {
|
|
3049
3206
|
setStatus(getTerminalBusyStatus(), "warning");
|
|
3050
3207
|
} else {
|
|
@@ -3065,6 +3222,9 @@
|
|
|
3065
3222
|
pendingRequestId = typeof message.requestId === "string" ? message.requestId : pendingRequestId;
|
|
3066
3223
|
pendingKind = typeof message.kind === "string" ? message.kind : "unknown";
|
|
3067
3224
|
stickyStudioKind = pendingKind;
|
|
3225
|
+
if (pendingKind === "direct") {
|
|
3226
|
+
studioRunChainActive = true;
|
|
3227
|
+
}
|
|
3068
3228
|
if (pendingKind === "compact") {
|
|
3069
3229
|
compactInProgress = true;
|
|
3070
3230
|
}
|
|
@@ -3074,6 +3234,14 @@
|
|
|
3074
3234
|
return;
|
|
3075
3235
|
}
|
|
3076
3236
|
|
|
3237
|
+
if (message.type === "request_queued") {
|
|
3238
|
+
studioRunChainActive = true;
|
|
3239
|
+
applyStudioRunQueueStateFromMessage(message);
|
|
3240
|
+
syncActionButtons();
|
|
3241
|
+
setStatus("Steering queued.", "success");
|
|
3242
|
+
return;
|
|
3243
|
+
}
|
|
3244
|
+
|
|
3077
3245
|
if (message.type === "compaction_completed") {
|
|
3078
3246
|
if (typeof message.requestId === "string" && pendingRequestId === message.requestId) {
|
|
3079
3247
|
pendingRequestId = null;
|
|
@@ -3310,6 +3478,7 @@
|
|
|
3310
3478
|
if (typeof message.terminalSessionLabel === "string") {
|
|
3311
3479
|
terminalSessionLabel = message.terminalSessionLabel;
|
|
3312
3480
|
}
|
|
3481
|
+
applyStudioRunQueueStateFromMessage(message);
|
|
3313
3482
|
updateFooterMeta();
|
|
3314
3483
|
|
|
3315
3484
|
if (typeof message.activeRequestId === "string" && message.activeRequestId.length > 0) {
|
|
@@ -3346,6 +3515,8 @@
|
|
|
3346
3515
|
if (busy) {
|
|
3347
3516
|
if (agentBusyFromServer && stickyStudioKind) {
|
|
3348
3517
|
setStatus(getStudioBusyStatus(stickyStudioKind), "warning");
|
|
3518
|
+
} else if (agentBusyFromServer && studioRunChainActive) {
|
|
3519
|
+
setStatus(getStudioBusyStatus("direct"), "warning");
|
|
3349
3520
|
} else if (agentBusyFromServer) {
|
|
3350
3521
|
setStatus(getTerminalBusyStatus(), "warning");
|
|
3351
3522
|
} else {
|
|
@@ -3816,8 +3987,8 @@
|
|
|
3816
3987
|
}
|
|
3817
3988
|
|
|
3818
3989
|
setEditorText(prompt, { preserveScroll: false, preserveSelection: false });
|
|
3819
|
-
setSourceState({ source: "blank", label:
|
|
3820
|
-
setStatus(
|
|
3990
|
+
setSourceState({ source: "blank", label: getHistoryPromptSourceStateLabel(item), path: null });
|
|
3991
|
+
setStatus(getHistoryPromptLoadedStatus(item), "success");
|
|
3821
3992
|
});
|
|
3822
3993
|
}
|
|
3823
3994
|
|
|
@@ -4118,6 +4289,30 @@
|
|
|
4118
4289
|
}
|
|
4119
4290
|
});
|
|
4120
4291
|
|
|
4292
|
+
if (queueSteerBtn) {
|
|
4293
|
+
queueSteerBtn.addEventListener("click", () => {
|
|
4294
|
+
const prepared = prepareEditorTextForSend(sourceTextEl.value);
|
|
4295
|
+
if (!prepared.trim()) {
|
|
4296
|
+
setStatus("Editor is empty. Nothing to queue.", "warning");
|
|
4297
|
+
return;
|
|
4298
|
+
}
|
|
4299
|
+
if (!studioRunChainActive) {
|
|
4300
|
+
setStatus("Queue steering is only available while Run editor text is active.", "warning");
|
|
4301
|
+
return;
|
|
4302
|
+
}
|
|
4303
|
+
|
|
4304
|
+
const requestId = makeRequestId();
|
|
4305
|
+
clearTitleAttention();
|
|
4306
|
+
const sent = sendMessage({
|
|
4307
|
+
type: "send_run_request",
|
|
4308
|
+
requestId,
|
|
4309
|
+
text: prepared,
|
|
4310
|
+
});
|
|
4311
|
+
if (!sent) return;
|
|
4312
|
+
setStatus("Queueing steering…", "warning");
|
|
4313
|
+
});
|
|
4314
|
+
}
|
|
4315
|
+
|
|
4121
4316
|
copyDraftBtn.addEventListener("click", async () => {
|
|
4122
4317
|
const content = sourceTextEl.value;
|
|
4123
4318
|
if (!content.trim()) {
|
package/client/studio.css
CHANGED
|
@@ -87,6 +87,7 @@
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
#sendRunBtn,
|
|
90
|
+
#queueSteerBtn,
|
|
90
91
|
#critiqueBtn {
|
|
91
92
|
min-width: 10rem;
|
|
92
93
|
display: inline-flex;
|
|
@@ -95,6 +96,7 @@
|
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
#sendRunBtn:not(:disabled):not(.request-stop-active),
|
|
99
|
+
#queueSteerBtn:not(:disabled),
|
|
98
100
|
#loadResponseBtn:not(:disabled):not([hidden]) {
|
|
99
101
|
background: var(--accent);
|
|
100
102
|
border-color: var(--accent);
|
|
@@ -103,6 +105,7 @@
|
|
|
103
105
|
}
|
|
104
106
|
|
|
105
107
|
#sendRunBtn:not(:disabled):not(.request-stop-active):hover,
|
|
108
|
+
#queueSteerBtn:not(:disabled):hover,
|
|
106
109
|
#loadResponseBtn:not(:disabled):not([hidden]):hover {
|
|
107
110
|
filter: brightness(0.95);
|
|
108
111
|
}
|
|
@@ -871,7 +874,9 @@
|
|
|
871
874
|
|
|
872
875
|
.rendered-markdown mjx-container[display="true"] {
|
|
873
876
|
display: block;
|
|
874
|
-
|
|
877
|
+
width: fit-content;
|
|
878
|
+
max-width: 100%;
|
|
879
|
+
margin: 1em auto;
|
|
875
880
|
text-align: center;
|
|
876
881
|
overflow-x: auto;
|
|
877
882
|
overflow-y: hidden;
|
|
@@ -890,7 +895,7 @@
|
|
|
890
895
|
|
|
891
896
|
.rendered-markdown .studio-display-equation-body math[display="block"],
|
|
892
897
|
.rendered-markdown .studio-display-equation-body mjx-container[display="true"] {
|
|
893
|
-
margin: 0;
|
|
898
|
+
margin: 0 auto;
|
|
894
899
|
}
|
|
895
900
|
|
|
896
901
|
.rendered-markdown .studio-display-equation-number {
|
|
@@ -907,7 +912,9 @@
|
|
|
907
912
|
|
|
908
913
|
.rendered-markdown math[display="block"] {
|
|
909
914
|
display: block;
|
|
910
|
-
|
|
915
|
+
width: fit-content;
|
|
916
|
+
max-width: 100%;
|
|
917
|
+
margin: 1em auto;
|
|
911
918
|
text-align: center;
|
|
912
919
|
overflow-x: auto;
|
|
913
920
|
overflow-y: hidden;
|