pi-studio 0.5.3 → 0.5.4
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 +12 -0
- package/README.md +2 -1
- package/index.ts +147 -26
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -88,6 +88,18 @@ All notable changes to `pi-studio` are documented here.
|
|
|
88
88
|
|
|
89
89
|
## [Unreleased]
|
|
90
90
|
|
|
91
|
+
## [0.5.4] — 2026-03-09
|
|
92
|
+
|
|
93
|
+
### Added
|
|
94
|
+
- New right-pane **Thinking (Raw)** view for assistant/model thinking when available.
|
|
95
|
+
|
|
96
|
+
### Changed
|
|
97
|
+
- Response history and latest-response syncing now preserve associated thinking content.
|
|
98
|
+
- In Thinking view, right-pane actions adapt to the selected reasoning trace:
|
|
99
|
+
- **Load thinking into editor**
|
|
100
|
+
- **Copy thinking text**
|
|
101
|
+
- thinking-aware reference/sync badges
|
|
102
|
+
|
|
91
103
|
## [0.5.3] — 2026-03-06
|
|
92
104
|
|
|
93
105
|
### Added
|
package/README.md
CHANGED
|
@@ -14,11 +14,12 @@ Experimental extension for [pi](https://github.com/badlogic/pi-mono) that opens
|
|
|
14
14
|
|
|
15
15
|
## What it does
|
|
16
16
|
|
|
17
|
-
- Opens a two-pane browser workspace: **Editor** (left) + **Response/Editor Preview** (right)
|
|
17
|
+
- Opens a two-pane browser workspace: **Editor** (left) + **Response/Thinking/Editor Preview** (right)
|
|
18
18
|
- Runs editor text directly, or asks for structured critique (auto/writing/code focus)
|
|
19
19
|
- Browses response history (`Prev/Next`) and loads either:
|
|
20
20
|
- response text
|
|
21
21
|
- critique notes/full critique
|
|
22
|
+
- assistant thinking (when available)
|
|
22
23
|
- the prompt that generated a selected response
|
|
23
24
|
- Supports an annotation workflow for `[an: ...]` markers:
|
|
24
25
|
- inserts/removes the annotated-reply header
|
package/index.ts
CHANGED
|
@@ -32,6 +32,7 @@ interface ActiveStudioRequest {
|
|
|
32
32
|
|
|
33
33
|
interface LastStudioResponse {
|
|
34
34
|
markdown: string;
|
|
35
|
+
thinking: string | null;
|
|
35
36
|
timestamp: number;
|
|
36
37
|
kind: StudioRequestKind;
|
|
37
38
|
}
|
|
@@ -39,6 +40,7 @@ interface LastStudioResponse {
|
|
|
39
40
|
interface StudioResponseHistoryItem {
|
|
40
41
|
id: string;
|
|
41
42
|
markdown: string;
|
|
43
|
+
thinking: string | null;
|
|
42
44
|
timestamp: number;
|
|
43
45
|
kind: StudioRequestKind;
|
|
44
46
|
prompt: string | null;
|
|
@@ -1259,6 +1261,27 @@ function extractAssistantText(message: unknown): string | null {
|
|
|
1259
1261
|
return text.length > 0 ? text : null;
|
|
1260
1262
|
}
|
|
1261
1263
|
|
|
1264
|
+
function extractAssistantThinking(message: unknown): string | null {
|
|
1265
|
+
const msg = message as {
|
|
1266
|
+
role?: string;
|
|
1267
|
+
content?: Array<{ type?: string; thinking?: string }> | string;
|
|
1268
|
+
};
|
|
1269
|
+
|
|
1270
|
+
if (!msg || msg.role !== "assistant" || !Array.isArray(msg.content)) return null;
|
|
1271
|
+
|
|
1272
|
+
const blocks: string[] = [];
|
|
1273
|
+
for (const part of msg.content) {
|
|
1274
|
+
if (!part || typeof part !== "object") continue;
|
|
1275
|
+
if (part.type !== "thinking") continue;
|
|
1276
|
+
if (typeof part.thinking === "string" && part.thinking.trim()) {
|
|
1277
|
+
blocks.push(part.thinking);
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
const thinking = blocks.join("\n\n").trim();
|
|
1282
|
+
return thinking.length > 0 ? thinking : null;
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1262
1285
|
function extractLatestAssistantFromEntries(entries: SessionEntry[]): string | null {
|
|
1263
1286
|
for (let i = entries.length - 1; i >= 0; i--) {
|
|
1264
1287
|
const entry = entries[i];
|
|
@@ -1330,9 +1353,11 @@ function buildResponseHistoryFromEntries(entries: SessionEntry[], limit = RESPON
|
|
|
1330
1353
|
if (role !== "assistant") continue;
|
|
1331
1354
|
const markdown = extractAssistantText(message);
|
|
1332
1355
|
if (!markdown) continue;
|
|
1356
|
+
const thinking = extractAssistantThinking(message);
|
|
1333
1357
|
history.push({
|
|
1334
1358
|
id: typeof (entry as { id?: unknown }).id === "string" ? (entry as { id: string }).id : randomUUID(),
|
|
1335
1359
|
markdown,
|
|
1360
|
+
thinking,
|
|
1336
1361
|
timestamp: parseEntryTimestamp((entry as { timestamp?: unknown }).timestamp),
|
|
1337
1362
|
kind: inferStudioResponseKind(markdown),
|
|
1338
1363
|
prompt: lastUserPrompt,
|
|
@@ -2889,6 +2914,7 @@ ${cssVarsBlock}
|
|
|
2889
2914
|
<option value="markdown">Response (Raw)</option>
|
|
2890
2915
|
<option value="preview" selected>Response (Preview)</option>
|
|
2891
2916
|
<option value="editor-preview">Editor (Preview)</option>
|
|
2917
|
+
<option value="thinking">Thinking (Raw)</option>
|
|
2892
2918
|
</select>
|
|
2893
2919
|
</div>
|
|
2894
2920
|
<div class="section-header-actions">
|
|
@@ -3043,11 +3069,13 @@ ${cssVarsBlock}
|
|
|
3043
3069
|
let followLatest = true;
|
|
3044
3070
|
let queuedLatestResponse = null;
|
|
3045
3071
|
let latestResponseMarkdown = "";
|
|
3072
|
+
let latestResponseThinking = "";
|
|
3046
3073
|
let latestResponseTimestamp = 0;
|
|
3047
3074
|
let latestResponseKind = "annotation";
|
|
3048
3075
|
let latestResponseIsStructuredCritique = false;
|
|
3049
3076
|
let latestResponseHasContent = false;
|
|
3050
3077
|
let latestResponseNormalized = "";
|
|
3078
|
+
let latestResponseThinkingNormalized = "";
|
|
3051
3079
|
let latestCritiqueNotes = "";
|
|
3052
3080
|
let latestCritiqueNotesNormalized = "";
|
|
3053
3081
|
let responseHistory = [];
|
|
@@ -3672,10 +3700,14 @@ ${cssVarsBlock}
|
|
|
3672
3700
|
const prompt = typeof item.prompt === "string"
|
|
3673
3701
|
? item.prompt
|
|
3674
3702
|
: (item.prompt == null ? null : String(item.prompt));
|
|
3703
|
+
const thinking = typeof item.thinking === "string"
|
|
3704
|
+
? item.thinking
|
|
3705
|
+
: (item.thinking == null ? null : String(item.thinking));
|
|
3675
3706
|
|
|
3676
3707
|
return {
|
|
3677
3708
|
id,
|
|
3678
3709
|
markdown,
|
|
3710
|
+
thinking,
|
|
3679
3711
|
timestamp,
|
|
3680
3712
|
kind: normalizeHistoryKind(item.kind),
|
|
3681
3713
|
prompt,
|
|
@@ -3690,11 +3722,13 @@ ${cssVarsBlock}
|
|
|
3690
3722
|
|
|
3691
3723
|
function clearActiveResponseView() {
|
|
3692
3724
|
latestResponseMarkdown = "";
|
|
3725
|
+
latestResponseThinking = "";
|
|
3693
3726
|
latestResponseKind = "annotation";
|
|
3694
3727
|
latestResponseTimestamp = 0;
|
|
3695
3728
|
latestResponseIsStructuredCritique = false;
|
|
3696
3729
|
latestResponseHasContent = false;
|
|
3697
3730
|
latestResponseNormalized = "";
|
|
3731
|
+
latestResponseThinkingNormalized = "";
|
|
3698
3732
|
latestCritiqueNotes = "";
|
|
3699
3733
|
latestCritiqueNotesNormalized = "";
|
|
3700
3734
|
refreshResponseUi();
|
|
@@ -3731,7 +3765,7 @@ ${cssVarsBlock}
|
|
|
3731
3765
|
clearActiveResponseView();
|
|
3732
3766
|
return false;
|
|
3733
3767
|
}
|
|
3734
|
-
handleIncomingResponse(item.markdown, item.kind, item.timestamp);
|
|
3768
|
+
handleIncomingResponse(item.markdown, item.kind, item.timestamp, item.thinking);
|
|
3735
3769
|
return true;
|
|
3736
3770
|
}
|
|
3737
3771
|
|
|
@@ -3814,6 +3848,26 @@ ${cssVarsBlock}
|
|
|
3814
3848
|
}
|
|
3815
3849
|
|
|
3816
3850
|
const hasResponse = Boolean(latestResponseMarkdown && latestResponseMarkdown.trim());
|
|
3851
|
+
const hasThinking = Boolean(latestResponseThinking && latestResponseThinking.trim());
|
|
3852
|
+
if (rightView === "thinking") {
|
|
3853
|
+
if (!hasResponse && !hasThinking) {
|
|
3854
|
+
referenceBadgeEl.textContent = "Thinking: none";
|
|
3855
|
+
return;
|
|
3856
|
+
}
|
|
3857
|
+
|
|
3858
|
+
const time = formatReferenceTime(latestResponseTimestamp);
|
|
3859
|
+
const total = Array.isArray(responseHistory) ? responseHistory.length : 0;
|
|
3860
|
+
const selected = total > 0 && responseHistoryIndex >= 0 && responseHistoryIndex < total
|
|
3861
|
+
? responseHistoryIndex + 1
|
|
3862
|
+
: 0;
|
|
3863
|
+
const historyPrefix = total > 0 ? "Response history " + selected + "/" + total + " · " : "";
|
|
3864
|
+
const thinkingLabel = hasThinking ? "assistant thinking" : "assistant thinking unavailable";
|
|
3865
|
+
referenceBadgeEl.textContent = time
|
|
3866
|
+
? historyPrefix + thinkingLabel + " · " + time
|
|
3867
|
+
: historyPrefix + thinkingLabel;
|
|
3868
|
+
return;
|
|
3869
|
+
}
|
|
3870
|
+
|
|
3817
3871
|
if (!hasResponse) {
|
|
3818
3872
|
referenceBadgeEl.textContent = "Latest response: none";
|
|
3819
3873
|
return;
|
|
@@ -3864,8 +3918,13 @@ ${cssVarsBlock}
|
|
|
3864
3918
|
function updateSyncBadge(normalizedEditorText) {
|
|
3865
3919
|
if (!syncBadgeEl) return;
|
|
3866
3920
|
|
|
3867
|
-
|
|
3868
|
-
|
|
3921
|
+
const showingThinking = rightView === "thinking";
|
|
3922
|
+
const hasComparableContent = showingThinking
|
|
3923
|
+
? Boolean(latestResponseThinking && latestResponseThinking.trim())
|
|
3924
|
+
: latestResponseHasContent;
|
|
3925
|
+
|
|
3926
|
+
if (!hasComparableContent) {
|
|
3927
|
+
syncBadgeEl.textContent = showingThinking ? "No thinking loaded" : "No response loaded";
|
|
3869
3928
|
syncBadgeEl.classList.remove("sync", "edited");
|
|
3870
3929
|
return;
|
|
3871
3930
|
}
|
|
@@ -3873,13 +3932,14 @@ ${cssVarsBlock}
|
|
|
3873
3932
|
const normalizedEditor = typeof normalizedEditorText === "string"
|
|
3874
3933
|
? normalizedEditorText
|
|
3875
3934
|
: normalizeForCompare(sourceTextEl.value);
|
|
3876
|
-
const
|
|
3935
|
+
const targetNormalized = showingThinking ? latestResponseThinkingNormalized : latestResponseNormalized;
|
|
3936
|
+
const inSync = normalizedEditor === targetNormalized;
|
|
3877
3937
|
if (inSync) {
|
|
3878
|
-
syncBadgeEl.textContent = "In sync with response";
|
|
3938
|
+
syncBadgeEl.textContent = showingThinking ? "In sync with thinking" : "In sync with response";
|
|
3879
3939
|
syncBadgeEl.classList.add("sync");
|
|
3880
3940
|
syncBadgeEl.classList.remove("edited");
|
|
3881
3941
|
} else {
|
|
3882
|
-
syncBadgeEl.textContent = "Out of sync with response";
|
|
3942
|
+
syncBadgeEl.textContent = showingThinking ? "Out of sync with thinking" : "Out of sync with response";
|
|
3883
3943
|
syncBadgeEl.classList.add("edited");
|
|
3884
3944
|
syncBadgeEl.classList.remove("sync");
|
|
3885
3945
|
}
|
|
@@ -4411,6 +4471,15 @@ ${cssVarsBlock}
|
|
|
4411
4471
|
return;
|
|
4412
4472
|
}
|
|
4413
4473
|
|
|
4474
|
+
if (rightView === "thinking") {
|
|
4475
|
+
const thinking = latestResponseThinking;
|
|
4476
|
+
finishPreviewRender(critiqueViewEl);
|
|
4477
|
+
critiqueViewEl.innerHTML = thinking && thinking.trim()
|
|
4478
|
+
? buildPlainMarkdownHtml(thinking)
|
|
4479
|
+
: "<pre class='plain-markdown'>No thinking available for this response.</pre>";
|
|
4480
|
+
return;
|
|
4481
|
+
}
|
|
4482
|
+
|
|
4414
4483
|
const markdown = latestResponseMarkdown;
|
|
4415
4484
|
if (!markdown || !markdown.trim()) {
|
|
4416
4485
|
finishPreviewRender(critiqueViewEl);
|
|
@@ -4446,36 +4515,56 @@ ${cssVarsBlock}
|
|
|
4446
4515
|
|
|
4447
4516
|
function updateResultActionButtons(normalizedEditorText) {
|
|
4448
4517
|
const hasResponse = latestResponseHasContent;
|
|
4518
|
+
const hasThinking = Boolean(latestResponseThinking && latestResponseThinking.trim());
|
|
4449
4519
|
const normalizedEditor = typeof normalizedEditorText === "string"
|
|
4450
4520
|
? normalizedEditorText
|
|
4451
4521
|
: normalizeForCompare(sourceTextEl.value);
|
|
4452
4522
|
const responseLoaded = hasResponse && normalizedEditor === latestResponseNormalized;
|
|
4523
|
+
const thinkingLoaded = hasThinking && normalizedEditor === latestResponseThinkingNormalized;
|
|
4453
4524
|
const isCritiqueResponse = hasResponse && latestResponseIsStructuredCritique;
|
|
4525
|
+
const showingThinking = rightView === "thinking";
|
|
4454
4526
|
|
|
4455
4527
|
const critiqueNotes = isCritiqueResponse ? latestCritiqueNotes : "";
|
|
4456
4528
|
const critiqueNotesLoaded = Boolean(critiqueNotes) && normalizedEditor === latestCritiqueNotesNormalized;
|
|
4457
4529
|
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4530
|
+
if (showingThinking) {
|
|
4531
|
+
loadResponseBtn.hidden = false;
|
|
4532
|
+
loadCritiqueNotesBtn.hidden = true;
|
|
4533
|
+
loadCritiqueFullBtn.hidden = true;
|
|
4534
|
+
|
|
4535
|
+
loadResponseBtn.disabled = uiBusy || !hasThinking || thinkingLoaded;
|
|
4536
|
+
loadResponseBtn.textContent = !hasThinking
|
|
4537
|
+
? "Thinking unavailable"
|
|
4538
|
+
: (thinkingLoaded ? "Thinking already in editor" : "Load thinking into editor");
|
|
4461
4539
|
|
|
4462
|
-
|
|
4463
|
-
|
|
4540
|
+
copyResponseBtn.disabled = uiBusy || !hasThinking;
|
|
4541
|
+
copyResponseBtn.textContent = "Copy thinking text";
|
|
4542
|
+
} else {
|
|
4543
|
+
loadResponseBtn.hidden = isCritiqueResponse;
|
|
4544
|
+
loadCritiqueNotesBtn.hidden = !isCritiqueResponse;
|
|
4545
|
+
loadCritiqueFullBtn.hidden = !isCritiqueResponse;
|
|
4464
4546
|
|
|
4465
|
-
|
|
4466
|
-
|
|
4547
|
+
loadResponseBtn.disabled = uiBusy || !hasResponse || responseLoaded || isCritiqueResponse;
|
|
4548
|
+
loadResponseBtn.textContent = responseLoaded ? "Response already in editor" : "Load response into editor";
|
|
4467
4549
|
|
|
4468
|
-
|
|
4469
|
-
|
|
4550
|
+
loadCritiqueNotesBtn.disabled = uiBusy || !isCritiqueResponse || !critiqueNotes || critiqueNotesLoaded;
|
|
4551
|
+
loadCritiqueNotesBtn.textContent = critiqueNotesLoaded ? "Critique notes already in editor" : "Load critique notes into editor";
|
|
4470
4552
|
|
|
4471
|
-
|
|
4553
|
+
loadCritiqueFullBtn.disabled = uiBusy || !isCritiqueResponse || responseLoaded;
|
|
4554
|
+
loadCritiqueFullBtn.textContent = responseLoaded ? "Full critique already in editor" : "Load full critique into editor";
|
|
4555
|
+
|
|
4556
|
+
copyResponseBtn.disabled = uiBusy || !hasResponse;
|
|
4557
|
+
copyResponseBtn.textContent = "Copy response text";
|
|
4558
|
+
}
|
|
4472
4559
|
|
|
4473
4560
|
const rightPaneShowsPreview = rightView === "preview" || rightView === "editor-preview";
|
|
4474
4561
|
const exportText = rightView === "editor-preview" ? prepareEditorTextForPreview(sourceTextEl.value) : latestResponseMarkdown;
|
|
4475
4562
|
const canExportPdf = rightPaneShowsPreview && Boolean(String(exportText || "").trim());
|
|
4476
4563
|
if (exportPdfBtn) {
|
|
4477
4564
|
exportPdfBtn.disabled = uiBusy || pdfExportInProgress || !canExportPdf;
|
|
4478
|
-
if (rightView === "
|
|
4565
|
+
if (rightView === "thinking") {
|
|
4566
|
+
exportPdfBtn.title = "Thinking view does not support PDF export yet.";
|
|
4567
|
+
} else if (rightView === "markdown") {
|
|
4479
4568
|
exportPdfBtn.title = "Switch right pane to Response (Preview) or Editor (Preview) to export PDF.";
|
|
4480
4569
|
} else if (!canExportPdf) {
|
|
4481
4570
|
exportPdfBtn.title = "Nothing to export yet.";
|
|
@@ -4653,7 +4742,11 @@ ${cssVarsBlock}
|
|
|
4653
4742
|
}
|
|
4654
4743
|
|
|
4655
4744
|
function setRightView(nextView) {
|
|
4656
|
-
rightView = nextView === "preview"
|
|
4745
|
+
rightView = nextView === "preview"
|
|
4746
|
+
? "preview"
|
|
4747
|
+
: (nextView === "editor-preview"
|
|
4748
|
+
? "editor-preview"
|
|
4749
|
+
: (nextView === "thinking" ? "thinking" : "markdown"));
|
|
4657
4750
|
rightViewSelect.value = rightView;
|
|
4658
4751
|
|
|
4659
4752
|
if (rightView !== "editor-preview" && responseEditorPreviewTimer) {
|
|
@@ -5330,18 +5423,20 @@ ${cssVarsBlock}
|
|
|
5330
5423
|
return lower.indexOf("## critiques") !== -1 && lower.indexOf("## document") !== -1;
|
|
5331
5424
|
}
|
|
5332
5425
|
|
|
5333
|
-
function handleIncomingResponse(markdown, kind, timestamp) {
|
|
5426
|
+
function handleIncomingResponse(markdown, kind, timestamp, thinking) {
|
|
5334
5427
|
const responseTimestamp =
|
|
5335
5428
|
typeof timestamp === "number" && Number.isFinite(timestamp) && timestamp > 0
|
|
5336
5429
|
? timestamp
|
|
5337
5430
|
: Date.now();
|
|
5338
5431
|
|
|
5339
5432
|
latestResponseMarkdown = markdown;
|
|
5433
|
+
latestResponseThinking = typeof thinking === "string" ? thinking : "";
|
|
5340
5434
|
latestResponseKind = kind === "critique" ? "critique" : "annotation";
|
|
5341
5435
|
latestResponseTimestamp = responseTimestamp;
|
|
5342
5436
|
latestResponseIsStructuredCritique = isStructuredCritique(markdown);
|
|
5343
5437
|
latestResponseHasContent = Boolean(markdown && markdown.trim());
|
|
5344
5438
|
latestResponseNormalized = normalizeForCompare(markdown);
|
|
5439
|
+
latestResponseThinkingNormalized = normalizeForCompare(latestResponseThinking);
|
|
5345
5440
|
|
|
5346
5441
|
if (latestResponseIsStructuredCritique) {
|
|
5347
5442
|
latestCritiqueNotes = buildCritiqueNotesMarkdown(markdown);
|
|
@@ -5357,7 +5452,7 @@ ${cssVarsBlock}
|
|
|
5357
5452
|
function applyLatestPayload(payload) {
|
|
5358
5453
|
if (!payload || typeof payload.markdown !== "string") return false;
|
|
5359
5454
|
const responseKind = payload.kind === "critique" ? "critique" : "annotation";
|
|
5360
|
-
handleIncomingResponse(payload.markdown, responseKind, payload.timestamp);
|
|
5455
|
+
handleIncomingResponse(payload.markdown, responseKind, payload.timestamp, payload.thinking);
|
|
5361
5456
|
return true;
|
|
5362
5457
|
}
|
|
5363
5458
|
|
|
@@ -5456,7 +5551,7 @@ ${cssVarsBlock}
|
|
|
5456
5551
|
message.lastResponse.kind === "critique"
|
|
5457
5552
|
? "critique"
|
|
5458
5553
|
: (isStructuredCritique(lastMarkdown) ? "critique" : "annotation");
|
|
5459
|
-
handleIncomingResponse(lastMarkdown, lastResponseKind, message.lastResponse.timestamp);
|
|
5554
|
+
handleIncomingResponse(lastMarkdown, lastResponseKind, message.lastResponse.timestamp, message.lastResponse.thinking);
|
|
5460
5555
|
}
|
|
5461
5556
|
|
|
5462
5557
|
if (pendingRequestId) {
|
|
@@ -5553,7 +5648,7 @@ ${cssVarsBlock}
|
|
|
5553
5648
|
}
|
|
5554
5649
|
|
|
5555
5650
|
if (!appliedFromHistory && typeof message.markdown === "string") {
|
|
5556
|
-
handleIncomingResponse(message.markdown, responseKind, message.timestamp);
|
|
5651
|
+
handleIncomingResponse(message.markdown, responseKind, message.timestamp, message.thinking);
|
|
5557
5652
|
}
|
|
5558
5653
|
|
|
5559
5654
|
if (responseKind === "critique") {
|
|
@@ -5582,6 +5677,7 @@ ${cssVarsBlock}
|
|
|
5582
5677
|
const payload = {
|
|
5583
5678
|
kind: message.kind === "critique" ? "critique" : "annotation",
|
|
5584
5679
|
markdown: message.markdown,
|
|
5680
|
+
thinking: typeof message.thinking === "string" ? message.thinking : null,
|
|
5585
5681
|
timestamp: message.timestamp,
|
|
5586
5682
|
};
|
|
5587
5683
|
|
|
@@ -6172,6 +6268,17 @@ ${cssVarsBlock}
|
|
|
6172
6268
|
});
|
|
6173
6269
|
|
|
6174
6270
|
loadResponseBtn.addEventListener("click", () => {
|
|
6271
|
+
if (rightView === "thinking") {
|
|
6272
|
+
if (!latestResponseThinking.trim()) {
|
|
6273
|
+
setStatus("No thinking available for the selected response.", "warning");
|
|
6274
|
+
return;
|
|
6275
|
+
}
|
|
6276
|
+
setEditorText(latestResponseThinking, { preserveScroll: false, preserveSelection: false });
|
|
6277
|
+
setSourceState({ source: "blank", label: "assistant thinking", path: null });
|
|
6278
|
+
setStatus("Loaded thinking into editor.", "success");
|
|
6279
|
+
return;
|
|
6280
|
+
}
|
|
6281
|
+
|
|
6175
6282
|
if (!latestResponseMarkdown.trim()) {
|
|
6176
6283
|
setStatus("No response available yet.", "warning");
|
|
6177
6284
|
return;
|
|
@@ -6210,14 +6317,15 @@ ${cssVarsBlock}
|
|
|
6210
6317
|
});
|
|
6211
6318
|
|
|
6212
6319
|
copyResponseBtn.addEventListener("click", async () => {
|
|
6213
|
-
|
|
6214
|
-
|
|
6320
|
+
const content = rightView === "thinking" ? latestResponseThinking : latestResponseMarkdown;
|
|
6321
|
+
if (!content.trim()) {
|
|
6322
|
+
setStatus(rightView === "thinking" ? "No thinking available yet." : "No response available yet.", "warning");
|
|
6215
6323
|
return;
|
|
6216
6324
|
}
|
|
6217
6325
|
|
|
6218
6326
|
try {
|
|
6219
|
-
await navigator.clipboard.writeText(
|
|
6220
|
-
setStatus("Copied response text.", "success");
|
|
6327
|
+
await navigator.clipboard.writeText(content);
|
|
6328
|
+
setStatus(rightView === "thinking" ? "Copied thinking text." : "Copied response text.", "success");
|
|
6221
6329
|
} catch (error) {
|
|
6222
6330
|
setStatus("Clipboard write failed.", "warning");
|
|
6223
6331
|
}
|
|
@@ -6635,6 +6743,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
6635
6743
|
}
|
|
6636
6744
|
lastStudioResponse = {
|
|
6637
6745
|
markdown: latest.markdown,
|
|
6746
|
+
thinking: latest.thinking,
|
|
6638
6747
|
timestamp: latest.timestamp,
|
|
6639
6748
|
kind: latest.kind,
|
|
6640
6749
|
};
|
|
@@ -6897,6 +7006,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
6897
7006
|
type: "latest_response",
|
|
6898
7007
|
kind: lastStudioResponse.kind,
|
|
6899
7008
|
markdown: lastStudioResponse.markdown,
|
|
7009
|
+
thinking: lastStudioResponse.thinking,
|
|
6900
7010
|
timestamp: lastStudioResponse.timestamp,
|
|
6901
7011
|
responseHistory: studioResponseHistory,
|
|
6902
7012
|
});
|
|
@@ -7711,11 +7821,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
7711
7821
|
const stopReason = typeof message.stopReason === "string" ? message.stopReason : "";
|
|
7712
7822
|
const role = typeof message.role === "string" ? message.role : "";
|
|
7713
7823
|
const markdown = extractAssistantText(event.message);
|
|
7824
|
+
const thinking = extractAssistantThinking(event.message);
|
|
7714
7825
|
emitDebugEvent("message_end", {
|
|
7715
7826
|
role,
|
|
7716
7827
|
stopReason,
|
|
7717
7828
|
hasMarkdown: Boolean(markdown),
|
|
7718
7829
|
markdownLength: markdown ? markdown.length : 0,
|
|
7830
|
+
hasThinking: Boolean(thinking),
|
|
7831
|
+
thinkingLength: thinking ? thinking.length : 0,
|
|
7719
7832
|
activeRequestId: activeRequest?.id ?? null,
|
|
7720
7833
|
activeRequestKind: activeRequest?.kind ?? null,
|
|
7721
7834
|
});
|
|
@@ -7742,6 +7855,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
7742
7855
|
const fallbackHistoryItem: StudioResponseHistoryItem = {
|
|
7743
7856
|
id: randomUUID(),
|
|
7744
7857
|
markdown,
|
|
7858
|
+
thinking,
|
|
7745
7859
|
timestamp: Date.now(),
|
|
7746
7860
|
kind: inferStudioResponseKind(markdown),
|
|
7747
7861
|
prompt: fallbackPrompt,
|
|
@@ -7752,12 +7866,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
7752
7866
|
|
|
7753
7867
|
const latestItem = studioResponseHistory[studioResponseHistory.length - 1];
|
|
7754
7868
|
const responseTimestamp = latestItem?.timestamp ?? Date.now();
|
|
7869
|
+
const responseThinking = latestItem?.thinking ?? thinking ?? null;
|
|
7755
7870
|
|
|
7756
7871
|
if (activeRequest) {
|
|
7757
7872
|
const requestId = activeRequest.id;
|
|
7758
7873
|
const kind = activeRequest.kind;
|
|
7759
7874
|
lastStudioResponse = {
|
|
7760
7875
|
markdown,
|
|
7876
|
+
thinking: responseThinking,
|
|
7761
7877
|
timestamp: responseTimestamp,
|
|
7762
7878
|
kind,
|
|
7763
7879
|
};
|
|
@@ -7765,6 +7881,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
7765
7881
|
requestId,
|
|
7766
7882
|
kind,
|
|
7767
7883
|
markdownLength: markdown.length,
|
|
7884
|
+
thinkingLength: responseThinking ? responseThinking.length : 0,
|
|
7768
7885
|
stopReason,
|
|
7769
7886
|
});
|
|
7770
7887
|
broadcast({
|
|
@@ -7772,6 +7889,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
7772
7889
|
requestId,
|
|
7773
7890
|
kind,
|
|
7774
7891
|
markdown,
|
|
7892
|
+
thinking: lastStudioResponse.thinking,
|
|
7775
7893
|
timestamp: lastStudioResponse.timestamp,
|
|
7776
7894
|
responseHistory: studioResponseHistory,
|
|
7777
7895
|
});
|
|
@@ -7783,18 +7901,21 @@ export default function (pi: ExtensionAPI) {
|
|
|
7783
7901
|
const inferredKind = inferStudioResponseKind(markdown);
|
|
7784
7902
|
lastStudioResponse = {
|
|
7785
7903
|
markdown,
|
|
7904
|
+
thinking: responseThinking,
|
|
7786
7905
|
timestamp: responseTimestamp,
|
|
7787
7906
|
kind: inferredKind,
|
|
7788
7907
|
};
|
|
7789
7908
|
emitDebugEvent("broadcast_latest_response", {
|
|
7790
7909
|
kind: inferredKind,
|
|
7791
7910
|
markdownLength: markdown.length,
|
|
7911
|
+
thinkingLength: responseThinking ? responseThinking.length : 0,
|
|
7792
7912
|
stopReason,
|
|
7793
7913
|
});
|
|
7794
7914
|
broadcast({
|
|
7795
7915
|
type: "latest_response",
|
|
7796
7916
|
kind: inferredKind,
|
|
7797
7917
|
markdown,
|
|
7918
|
+
thinking: lastStudioResponse.thinking,
|
|
7798
7919
|
timestamp: lastStudioResponse.timestamp,
|
|
7799
7920
|
responseHistory: studioResponseHistory,
|
|
7800
7921
|
});
|