pi-studio 0.5.58 → 0.6.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/client/studio.css CHANGED
@@ -2113,7 +2113,13 @@
2113
2113
 
2114
2114
  .review-notes-dock-footer .scratchpad-actions {
2115
2115
  width: 100%;
2116
- justify-content: space-between;
2116
+ gap: 6px;
2117
+ justify-content: flex-end;
2118
+ }
2119
+
2120
+ .review-notes-dock-footer .scratchpad-actions button {
2121
+ padding: 5px 7px;
2122
+ font-size: 11px;
2117
2123
  }
2118
2124
 
2119
2125
  .outline-list {
@@ -2314,3 +2320,579 @@
2314
2320
  grid-template-columns: 1fr;
2315
2321
  }
2316
2322
  }
2323
+
2324
+ /* Default refreshed Studio layout. Classic layout remains available with ?uiRefresh=0 or the footer UI switch. */
2325
+ body.studio-ui-refresh {
2326
+ font-size: 13px;
2327
+ }
2328
+
2329
+ body.studio-ui-refresh > header {
2330
+ padding: 8px 12px;
2331
+ gap: 9px;
2332
+ }
2333
+
2334
+ body.studio-ui-refresh h1 {
2335
+ font-size: 16px;
2336
+ }
2337
+
2338
+ body.studio-ui-refresh .app-logo {
2339
+ font-size: 18px;
2340
+ }
2341
+
2342
+ body.studio-ui-refresh .app-subtitle {
2343
+ font-size: 10px;
2344
+ }
2345
+
2346
+ body.studio-ui-refresh > header .controls {
2347
+ gap: 5px;
2348
+ }
2349
+
2350
+ body.studio-ui-refresh > header button,
2351
+ body.studio-ui-refresh > header .file-label,
2352
+ body.studio-ui-refresh #responseActions button,
2353
+ body.studio-ui-refresh #responseActions select {
2354
+ padding: 5px 7px;
2355
+ font-size: 12px;
2356
+ }
2357
+
2358
+ body.studio-ui-refresh main {
2359
+ gap: 9px;
2360
+ padding: 9px;
2361
+ }
2362
+
2363
+ body.studio-ui-refresh footer {
2364
+ padding: 7px 9px;
2365
+ font-size: 11px;
2366
+ }
2367
+
2368
+ .studio-ui-refresh-toggle {
2369
+ opacity: 0.9;
2370
+ }
2371
+
2372
+ .studio-ui-refresh-toggle:not(:disabled):hover {
2373
+ opacity: 1;
2374
+ }
2375
+
2376
+ body.studio-ui-refresh[data-studio-mode="editor-only"] #leftSectionHeader .section-header-main::before,
2377
+ body.studio-ui-refresh[data-studio-mode="editor-only"] #rightSectionHeader .section-header-main::before {
2378
+ content: none;
2379
+ display: none;
2380
+ }
2381
+
2382
+ body.studio-ui-refresh #leftSectionHeader,
2383
+ body.studio-ui-refresh #rightSectionHeader {
2384
+ position: relative;
2385
+ z-index: 30;
2386
+ display: grid;
2387
+ gap: 6px;
2388
+ background: transparent;
2389
+ padding: 7px 9px 6px;
2390
+ overflow: visible;
2391
+ }
2392
+
2393
+ body.studio-ui-refresh #leftSectionHeader {
2394
+ grid-template-columns: 1fr;
2395
+ align-items: stretch;
2396
+ }
2397
+
2398
+ body.studio-ui-refresh #rightSectionHeader {
2399
+ grid-template-columns: minmax(0, 1fr) auto;
2400
+ align-items: center;
2401
+ }
2402
+
2403
+ body.studio-ui-refresh .studio-refresh-utility-left,
2404
+ body.studio-ui-refresh .studio-refresh-pane-identity,
2405
+ body.studio-ui-refresh .studio-refresh-pane-tools,
2406
+ body.studio-ui-refresh .studio-refresh-title-group,
2407
+ body.studio-ui-refresh .studio-refresh-context-group,
2408
+ body.studio-ui-refresh .studio-refresh-action-line {
2409
+ display: flex;
2410
+ align-items: center;
2411
+ gap: 6px;
2412
+ min-width: 0;
2413
+ flex-wrap: wrap;
2414
+ }
2415
+
2416
+ body.studio-ui-refresh .studio-refresh-header-top,
2417
+ body.studio-ui-refresh .studio-refresh-header-utility {
2418
+ display: grid;
2419
+ grid-template-columns: minmax(0, 1fr) auto;
2420
+ align-items: center;
2421
+ gap: 9px;
2422
+ min-width: 0;
2423
+ }
2424
+
2425
+ body.studio-ui-refresh .studio-refresh-pane-identity {
2426
+ display: grid;
2427
+ grid-template-columns: auto minmax(0, 1fr);
2428
+ align-items: center;
2429
+ column-gap: 9px;
2430
+ row-gap: 5px;
2431
+ }
2432
+
2433
+ body.studio-ui-refresh .studio-refresh-title-group,
2434
+ body.studio-ui-refresh .studio-refresh-context-group,
2435
+ body.studio-ui-refresh .studio-refresh-utility-left {
2436
+ flex-wrap: nowrap;
2437
+ }
2438
+
2439
+ body.studio-ui-refresh .studio-refresh-context-group,
2440
+ body.studio-ui-refresh .studio-refresh-utility-left {
2441
+ overflow: hidden;
2442
+ white-space: nowrap;
2443
+ }
2444
+
2445
+ body.studio-ui-refresh .studio-refresh-title-group {
2446
+ gap: 2px;
2447
+ }
2448
+
2449
+ body.studio-ui-refresh .studio-refresh-pane-tools {
2450
+ justify-content: flex-end;
2451
+ flex-wrap: nowrap;
2452
+ }
2453
+
2454
+ body.studio-ui-refresh .studio-refresh-sep {
2455
+ display: inline-block;
2456
+ width: 1px;
2457
+ height: 16px;
2458
+ background: var(--border-muted);
2459
+ margin: 0 1px;
2460
+ flex: 0 0 1px;
2461
+ }
2462
+
2463
+ body.studio-ui-refresh .studio-refresh-icon {
2464
+ width: 15px;
2465
+ height: 15px;
2466
+ stroke: currentColor;
2467
+ stroke-width: 1.85;
2468
+ stroke-linecap: round;
2469
+ stroke-linejoin: round;
2470
+ fill: none;
2471
+ pointer-events: none;
2472
+ }
2473
+
2474
+ body.studio-ui-refresh #leftSectionHeader select,
2475
+ body.studio-ui-refresh #leftSectionHeader button,
2476
+ body.studio-ui-refresh #rightSectionHeader select,
2477
+ body.studio-ui-refresh #rightSectionHeader button,
2478
+ body.studio-ui-refresh .studio-refresh-toolbar button,
2479
+ body.studio-ui-refresh .studio-refresh-toolbar select {
2480
+ border-color: transparent;
2481
+ background: transparent;
2482
+ font-size: 13px;
2483
+ }
2484
+
2485
+ body.studio-ui-refresh #leftSectionHeader select:hover,
2486
+ body.studio-ui-refresh #leftSectionHeader button:not(:disabled):hover,
2487
+ body.studio-ui-refresh #rightSectionHeader select:hover,
2488
+ body.studio-ui-refresh #rightSectionHeader button:not(:disabled):hover,
2489
+ body.studio-ui-refresh .studio-refresh-toolbar button:not(:disabled):hover,
2490
+ body.studio-ui-refresh .studio-refresh-toolbar select:not(:disabled):hover {
2491
+ background: var(--panel-2);
2492
+ }
2493
+
2494
+ body.studio-ui-refresh #leftSectionHeader #editorViewSelect,
2495
+ body.studio-ui-refresh #rightSectionHeader #rightViewSelect {
2496
+ font-size: 14px;
2497
+ font-weight: 750;
2498
+ padding: 3px 5px;
2499
+ max-width: 230px;
2500
+ }
2501
+
2502
+ body.studio-ui-refresh .studio-refresh-static-title {
2503
+ color: var(--text);
2504
+ font-size: 14px;
2505
+ font-weight: 700;
2506
+ padding: 3px 5px;
2507
+ max-width: 230px;
2508
+ white-space: nowrap;
2509
+ }
2510
+
2511
+ body.studio-ui-refresh #leftFocusBtn,
2512
+ body.studio-ui-refresh #rightFocusBtn {
2513
+ width: 29px;
2514
+ min-width: 29px;
2515
+ min-height: 29px;
2516
+ padding: 0;
2517
+ color: var(--muted);
2518
+ align-items: center;
2519
+ justify-content: center;
2520
+ }
2521
+
2522
+ body.studio-ui-refresh #sourceBadge,
2523
+ body.studio-ui-refresh #resourceDirBtn,
2524
+ body.studio-ui-refresh #resourceDirLabel {
2525
+ border-color: transparent;
2526
+ background: transparent;
2527
+ padding: 3px 5px;
2528
+ font-size: 13px;
2529
+ border-radius: 8px;
2530
+ }
2531
+
2532
+ body.studio-ui-refresh #sourceBadge {
2533
+ color: var(--text);
2534
+ max-width: min(34rem, 54vw);
2535
+ min-width: 0;
2536
+ overflow: hidden;
2537
+ text-overflow: ellipsis;
2538
+ white-space: nowrap;
2539
+ }
2540
+
2541
+ body.studio-ui-refresh #resourceDirBtn,
2542
+ body.studio-ui-refresh #resourceDirLabel,
2543
+ body.studio-ui-refresh #reviewNotesBtn,
2544
+ body.studio-ui-refresh #outlineBtn,
2545
+ body.studio-ui-refresh #scratchpadBtn,
2546
+ body.studio-ui-refresh .studio-refresh-tool-tab {
2547
+ color: var(--text);
2548
+ }
2549
+
2550
+ body.studio-ui-refresh #resourceDirInputWrap.visible {
2551
+ display: inline-flex;
2552
+ }
2553
+
2554
+ body.studio-ui-refresh #syncBadge {
2555
+ display: inline-flex;
2556
+ align-items: center;
2557
+ gap: 5px;
2558
+ min-height: 24px;
2559
+ border: 0;
2560
+ border-radius: 999px;
2561
+ padding: 2px 8px;
2562
+ background: var(--panel-2);
2563
+ color: var(--muted);
2564
+ opacity: 1;
2565
+ }
2566
+
2567
+ body.studio-ui-refresh #syncBadge[hidden] {
2568
+ display: none !important;
2569
+ }
2570
+
2571
+ body.studio-ui-refresh #syncBadge::before {
2572
+ content: "";
2573
+ width: 6px;
2574
+ height: 6px;
2575
+ border-radius: 999px;
2576
+ background: var(--success, #22c55e);
2577
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--success, #22c55e) 14%, transparent);
2578
+ }
2579
+
2580
+ body.studio-ui-refresh #reviewNotesBtn,
2581
+ body.studio-ui-refresh #outlineBtn,
2582
+ body.studio-ui-refresh #scratchpadBtn,
2583
+ body.studio-ui-refresh #exportPdfBtn,
2584
+ body.studio-ui-refresh .studio-refresh-tool-tab {
2585
+ font-weight: 500;
2586
+ padding: 5px 8px;
2587
+ border-radius: 8px;
2588
+ }
2589
+
2590
+ body.studio-ui-refresh #exportPdfBtn {
2591
+ background: var(--panel-2);
2592
+ color: var(--text);
2593
+ border-color: transparent;
2594
+ }
2595
+
2596
+ body.studio-ui-refresh #reviewNotesBtn.is-active,
2597
+ body.studio-ui-refresh #outlineBtn.is-active,
2598
+ body.studio-ui-refresh #scratchpadBtn.has-content,
2599
+ body.studio-ui-refresh #reviewNotesBtn.has-content {
2600
+ background: var(--accent-soft);
2601
+ color: var(--accent);
2602
+ border-color: transparent;
2603
+ }
2604
+
2605
+ body.studio-ui-refresh .source-wrap {
2606
+ padding: 0;
2607
+ gap: 0;
2608
+ }
2609
+
2610
+ body.studio-ui-refresh .source-meta {
2611
+ display: block;
2612
+ padding: 0;
2613
+ border-bottom: 1px solid var(--border-muted);
2614
+ position: relative;
2615
+ z-index: 20;
2616
+ overflow: visible;
2617
+ }
2618
+
2619
+ body.studio-ui-refresh .source-body {
2620
+ padding: 7px;
2621
+ }
2622
+
2623
+ body.studio-ui-refresh textarea {
2624
+ font-size: 12px;
2625
+ line-height: 1.42;
2626
+ }
2627
+
2628
+ body.studio-ui-refresh .editor-highlight,
2629
+ body.studio-ui-refresh .editor-line-number-measure {
2630
+ font-size: 12px;
2631
+ line-height: 1.42;
2632
+ }
2633
+
2634
+ body.studio-ui-refresh #sourceText,
2635
+ body.studio-ui-refresh .editor-highlight {
2636
+ padding: 9px 9px 9px calc(9px + var(--editor-review-note-gutter-width) + var(--editor-line-number-gutter-width));
2637
+ }
2638
+
2639
+ body.studio-ui-refresh .editor-line-number-gutter-content {
2640
+ padding: 9px 7px 9px 0;
2641
+ font-size: 11px;
2642
+ line-height: 1.42;
2643
+ }
2644
+
2645
+ body.studio-ui-refresh .editor-review-note-gutter-content {
2646
+ padding: 9px 4px;
2647
+ }
2648
+
2649
+ body.studio-ui-refresh .panel-scroll {
2650
+ padding: 11px;
2651
+ line-height: 1.48;
2652
+ font-size: 13px;
2653
+ }
2654
+
2655
+ body.studio-ui-refresh .rendered-markdown {
2656
+ line-height: 1.52;
2657
+ font-size: 13.5px;
2658
+ }
2659
+
2660
+ body.studio-ui-refresh .plain-markdown,
2661
+ body.studio-ui-refresh .response-markdown-highlight {
2662
+ font-size: 12px;
2663
+ line-height: 1.42;
2664
+ }
2665
+
2666
+ body.studio-ui-refresh .rendered-markdown pre {
2667
+ padding: 11px 13px;
2668
+ }
2669
+
2670
+ body.studio-ui-refresh .trace-panel,
2671
+ body.studio-ui-refresh .trace-card,
2672
+ body.studio-ui-refresh .trace-toolbar,
2673
+ body.studio-ui-refresh .trace-summary,
2674
+ body.studio-ui-refresh .trace-controls,
2675
+ body.studio-ui-refresh .trace-card-header {
2676
+ gap: 7px;
2677
+ }
2678
+
2679
+ body.studio-ui-refresh .trace-card {
2680
+ padding: 9px 11px;
2681
+ }
2682
+
2683
+ body.studio-ui-refresh .trace-output {
2684
+ padding: 9px 10px;
2685
+ font-size: 12px;
2686
+ line-height: 1.42;
2687
+ }
2688
+
2689
+ body.studio-ui-refresh .studio-refresh-toolbar {
2690
+ position: relative;
2691
+ padding: 8px 10px 9px;
2692
+ overflow: visible;
2693
+ }
2694
+
2695
+ body.studio-ui-refresh .studio-refresh-toolbar-main {
2696
+ display: grid;
2697
+ grid-template-columns: minmax(0, 1fr) auto;
2698
+ gap: 10px;
2699
+ align-items: start;
2700
+ min-width: 0;
2701
+ }
2702
+
2703
+ body.studio-ui-refresh .studio-refresh-toolbar-actions {
2704
+ display: grid;
2705
+ gap: 6px;
2706
+ justify-items: start;
2707
+ min-width: 0;
2708
+ }
2709
+
2710
+ body.studio-ui-refresh .studio-refresh-toolbar-state {
2711
+ display: grid;
2712
+ gap: 6px;
2713
+ justify-items: end;
2714
+ align-content: start;
2715
+ min-width: max-content;
2716
+ }
2717
+
2718
+ body.studio-ui-refresh .studio-refresh-chip {
2719
+ display: inline-flex;
2720
+ align-items: center;
2721
+ gap: 5px;
2722
+ border-radius: 8px;
2723
+ color: var(--text);
2724
+ white-space: nowrap;
2725
+ padding: 5px 8px;
2726
+ font-size: 13px;
2727
+ }
2728
+
2729
+ body.studio-ui-refresh .studio-refresh-chip::after {
2730
+ content: "⌄";
2731
+ color: var(--muted);
2732
+ font-size: 14px;
2733
+ line-height: 1;
2734
+ transform: translateY(-1px);
2735
+ }
2736
+
2737
+ body.studio-ui-refresh .studio-refresh-chip.is-open {
2738
+ background: var(--panel-2);
2739
+ color: var(--text);
2740
+ }
2741
+
2742
+ body.studio-ui-refresh .studio-refresh-menu-anchor {
2743
+ position: relative;
2744
+ display: inline-flex;
2745
+ align-items: center;
2746
+ overflow: visible;
2747
+ }
2748
+
2749
+ body.studio-ui-refresh .studio-refresh-menu {
2750
+ position: absolute;
2751
+ top: calc(100% + 8px);
2752
+ right: 0;
2753
+ width: min(420px, calc(100vw - 48px));
2754
+ padding: 10px;
2755
+ border: 1px solid var(--border);
2756
+ border-radius: 12px;
2757
+ background: var(--panel);
2758
+ box-shadow: 0 18px 46px rgba(0, 0, 0, 0.32);
2759
+ z-index: 100;
2760
+ }
2761
+
2762
+ body.studio-ui-refresh .studio-refresh-review-anchor .studio-refresh-menu {
2763
+ width: min(360px, calc(100vw - 48px));
2764
+ left: auto;
2765
+ right: 0;
2766
+ }
2767
+
2768
+ body.studio-ui-refresh .studio-refresh-view-anchor .studio-refresh-menu {
2769
+ width: min(320px, calc(100vw - 48px));
2770
+ }
2771
+
2772
+ body.studio-ui-refresh .studio-refresh-menu[hidden] {
2773
+ display: none !important;
2774
+ }
2775
+
2776
+ body.studio-ui-refresh .studio-refresh-menu-section {
2777
+ padding: 8px 0 6px;
2778
+ border-top: 1px solid var(--border-muted);
2779
+ }
2780
+
2781
+ body.studio-ui-refresh .studio-refresh-menu-section:first-child {
2782
+ border-top: 0;
2783
+ padding-top: 0;
2784
+ }
2785
+
2786
+ body.studio-ui-refresh .studio-refresh-menu-heading {
2787
+ margin: 0 6px 6px;
2788
+ color: var(--muted);
2789
+ font-size: 11px;
2790
+ font-weight: 700;
2791
+ text-transform: uppercase;
2792
+ letter-spacing: 0.08em;
2793
+ }
2794
+
2795
+ body.studio-ui-refresh .studio-refresh-menu-item {
2796
+ display: flex;
2797
+ align-items: center;
2798
+ gap: 8px;
2799
+ padding: 4px 0;
2800
+ min-width: 0;
2801
+ }
2802
+
2803
+ body.studio-ui-refresh .studio-refresh-menu-item > button,
2804
+ body.studio-ui-refresh .studio-refresh-menu-item > select {
2805
+ width: 100%;
2806
+ justify-content: flex-start;
2807
+ text-align: left;
2808
+ border-color: transparent;
2809
+ background: transparent;
2810
+ color: var(--text);
2811
+ }
2812
+
2813
+ body.studio-ui-refresh .studio-refresh-menu #critiqueBtn {
2814
+ justify-content: flex-start;
2815
+ text-align: left;
2816
+ }
2817
+
2818
+ body.studio-ui-refresh .studio-refresh-menu-item > button:not(:disabled):hover,
2819
+ body.studio-ui-refresh .studio-refresh-menu-item > select:not(:disabled):hover {
2820
+ background: var(--panel-2);
2821
+ }
2822
+
2823
+ body.studio-ui-refresh #copyDraftBtn:only-child {
2824
+ min-height: 29px;
2825
+ padding: 4px 8px;
2826
+ }
2827
+
2828
+ body.studio-ui-refresh #sendRunBtn,
2829
+ body.studio-ui-refresh #queueSteerBtn,
2830
+ body.studio-ui-refresh #loadResponseBtn:not([hidden]) {
2831
+ height: 28px;
2832
+ min-height: 28px;
2833
+ padding: 4px 9px;
2834
+ font-size: 12px;
2835
+ line-height: 1.2;
2836
+ border-radius: 8px;
2837
+ }
2838
+
2839
+ body.studio-ui-refresh #sendRunBtn,
2840
+ body.studio-ui-refresh #queueSteerBtn {
2841
+ min-width: 8.6rem;
2842
+ }
2843
+
2844
+ body.studio-ui-refresh #queueSteerBtn:not(:disabled) {
2845
+ background: var(--accent);
2846
+ border-color: var(--accent);
2847
+ color: var(--accent-contrast);
2848
+ font-weight: 600;
2849
+ }
2850
+
2851
+ body.studio-ui-refresh #queueSteerBtn:not(:disabled):hover {
2852
+ background: var(--accent);
2853
+ filter: brightness(0.95);
2854
+ }
2855
+
2856
+ body.studio-ui-refresh .studio-refresh-review-btn.request-stop-active {
2857
+ background: var(--error);
2858
+ border-color: var(--error);
2859
+ color: var(--error-contrast);
2860
+ font-weight: 600;
2861
+ }
2862
+
2863
+ body.studio-ui-refresh .studio-refresh-review-btn.request-stop-active::after {
2864
+ content: none;
2865
+ }
2866
+
2867
+ body.studio-ui-refresh .studio-refresh-menu #critiqueBtn.request-stop-active {
2868
+ background: var(--error);
2869
+ border-color: var(--error);
2870
+ color: var(--error-contrast);
2871
+ font-weight: 600;
2872
+ }
2873
+
2874
+ @media (max-width: 1280px) {
2875
+ body.studio-ui-refresh #rightSectionHeader,
2876
+ body.studio-ui-refresh .studio-refresh-header-top,
2877
+ body.studio-ui-refresh .studio-refresh-header-utility,
2878
+ body.studio-ui-refresh .studio-refresh-toolbar-main,
2879
+ body.studio-ui-refresh .studio-refresh-pane-identity {
2880
+ grid-template-columns: 1fr;
2881
+ }
2882
+
2883
+ body.studio-ui-refresh .studio-refresh-pane-tools,
2884
+ body.studio-ui-refresh .studio-refresh-toolbar-state {
2885
+ justify-content: flex-start;
2886
+ justify-items: start;
2887
+ }
2888
+
2889
+ body.studio-ui-refresh .studio-refresh-pane-tools,
2890
+ body.studio-ui-refresh .studio-refresh-title-group,
2891
+ body.studio-ui-refresh .studio-refresh-utility-left {
2892
+ flex-wrap: wrap;
2893
+ }
2894
+
2895
+ body.studio-ui-refresh .studio-refresh-toolbar-state {
2896
+ min-width: 0;
2897
+ }
2898
+ }
package/index.ts CHANGED
@@ -5764,34 +5764,74 @@ function createEmptyStudioTraceState(): StudioTraceState {
5764
5764
  };
5765
5765
  }
5766
5766
 
5767
+ function sanitizeStudioTraceOutputText(text: string): string {
5768
+ return String(text || "")
5769
+ .replace(/data:image\/([a-zA-Z0-9.+-]+);base64,[A-Za-z0-9+/=\r\n]+/g, (_match, subtype: string) => `[Image: image/${subtype || "unknown"} data omitted]`)
5770
+ .replace(/(\"(?:data|image|base64|content)\"\s*:\s*\")[A-Za-z0-9+/=]{1000,}(\")/g, "$1[base64 data omitted]$2")
5771
+ .replace(/\b[A-Za-z0-9+/]{3000,}={0,2}\b/g, "[base64 data omitted]");
5772
+ }
5773
+
5774
+ function isStudioTraceImageBlock(block: unknown): boolean {
5775
+ if (!block || typeof block !== "object") return false;
5776
+ const payload = block as Record<string, unknown>;
5777
+ const type = typeof payload.type === "string" ? payload.type.toLowerCase() : "";
5778
+ if (type.includes("image")) return true;
5779
+ const mime = typeof payload.mimeType === "string"
5780
+ ? payload.mimeType
5781
+ : (typeof payload.media_type === "string" ? payload.media_type : "");
5782
+ if (mime.toLowerCase().startsWith("image/")) return true;
5783
+ const source = payload.source && typeof payload.source === "object" ? payload.source as Record<string, unknown> : null;
5784
+ const sourceMime = source && typeof source.media_type === "string" ? source.media_type : "";
5785
+ return sourceMime.toLowerCase().startsWith("image/");
5786
+ }
5787
+
5788
+ function describeStudioTraceImageBlock(block: unknown): string {
5789
+ const payload = (block && typeof block === "object") ? block as Record<string, unknown> : {};
5790
+ const source = payload.source && typeof payload.source === "object" ? payload.source as Record<string, unknown> : null;
5791
+ const mime = typeof payload.mimeType === "string"
5792
+ ? payload.mimeType
5793
+ : (typeof payload.media_type === "string"
5794
+ ? payload.media_type
5795
+ : (source && typeof source.media_type === "string" ? source.media_type : "image"));
5796
+ return `[Image: ${mime || "image"} output omitted from Working view]`;
5797
+ }
5798
+
5799
+ function stringifyStudioTraceObject(value: unknown): string {
5800
+ try {
5801
+ return sanitizeStudioTraceOutputText(JSON.stringify(value, (_key, item) => {
5802
+ if (typeof item === "string") {
5803
+ if (/^data:image\//i.test(item)) return "[image data URI omitted]";
5804
+ if (/^[A-Za-z0-9+/=]{1000,}$/.test(item)) return "[base64 data omitted]";
5805
+ }
5806
+ return item;
5807
+ }, 2));
5808
+ } catch {
5809
+ return sanitizeStudioTraceOutputText(String(value));
5810
+ }
5811
+ }
5812
+
5767
5813
  function formatStudioTraceOutput(result: unknown): string {
5768
5814
  if (result == null) return "";
5769
- if (typeof result === "string") return result;
5815
+ if (typeof result === "string") return sanitizeStudioTraceOutputText(result);
5770
5816
  if (Array.isArray(result)) {
5771
5817
  return result.map((item) => formatStudioTraceOutput(item)).filter(Boolean).join("\n");
5772
5818
  }
5773
5819
  if (typeof result === "object") {
5820
+ if (isStudioTraceImageBlock(result)) return describeStudioTraceImageBlock(result);
5774
5821
  const payload = result as { content?: Array<{ type?: string; text?: string }> };
5775
5822
  if (Array.isArray(payload.content)) {
5776
5823
  return payload.content
5777
5824
  .map((block) => {
5778
- if (block && block.type === "text" && typeof block.text === "string") return block.text;
5779
- try {
5780
- return JSON.stringify(block, null, 2);
5781
- } catch {
5782
- return String(block);
5783
- }
5825
+ if (isStudioTraceImageBlock(block)) return describeStudioTraceImageBlock(block);
5826
+ if (block && block.type === "text" && typeof block.text === "string") return sanitizeStudioTraceOutputText(block.text);
5827
+ return stringifyStudioTraceObject(block);
5784
5828
  })
5785
5829
  .filter(Boolean)
5786
5830
  .join("\n");
5787
5831
  }
5788
- try {
5789
- return JSON.stringify(result, null, 2);
5790
- } catch {
5791
- return String(result);
5792
- }
5832
+ return stringifyStudioTraceObject(result);
5793
5833
  }
5794
- return String(result);
5834
+ return sanitizeStudioTraceOutputText(String(result));
5795
5835
  }
5796
5836
 
5797
5837
  function summarizeStudioTraceToolArgs(toolName: string, args: unknown): string | null {
@@ -6260,8 +6300,9 @@ ${cssVarsBlock}
6260
6300
  <div id="reviewNotesList" class="review-notes-list" aria-live="polite"></div>
6261
6301
  <div class="review-notes-dock-footer">
6262
6302
  <div class="scratchpad-actions">
6263
- <button id="reviewNotesAddBtn" type="button" title="Create a new local comment on the current editor line.">Line comment</button>
6264
- <button id="reviewNotesInlineAllBtn" type="button" title="Toggle inline annotations for all non-empty comments.">All inline: Off</button>
6303
+ <button id="reviewNotesAddBtn" type="button" title="Create a new local comment on the current editor line.">Line</button>
6304
+ <button id="reviewNotesPromptBtn" type="button" title="Load local comments, line numbers, and file labels into the editor as a prompt.">Comments prompt</button>
6305
+ <button id="reviewNotesInlineAllBtn" type="button" title="Toggle inline annotations for all non-empty comments.">Inline: Off</button>
6265
6306
  <button id="reviewNotesDeleteAllBtn" type="button" title="Delete all local comments for this document or draft.">Delete all</button>
6266
6307
  <button id="reviewNotesDoneBtn" type="button" title="Hide the comments rail.">Hide</button>
6267
6308
  </div>
@@ -7228,6 +7269,20 @@ export default function (pi: ExtensionAPI) {
7228
7269
  promptTriggerText: descriptor.promptTriggerText,
7229
7270
  };
7230
7271
  queuedStudioDirectRequests.push(queuedRequest);
7272
+
7273
+ // Steering is delivered into the currently running Studio turn rather than
7274
+ // becoming a fully separate visible response request. Keep the active direct
7275
+ // request metadata aligned with the effective prompt chain so persisted
7276
+ // prompt metadata, response history, and "Load effective prompt" all refer
7277
+ // to the original run plus queued steering, not just the original run.
7278
+ if (activeRequest && activeRequest.kind === "direct") {
7279
+ activeRequest.prompt = descriptor.prompt;
7280
+ activeRequest.promptMode = descriptor.promptMode;
7281
+ activeRequest.promptTriggerKind = descriptor.promptTriggerKind;
7282
+ activeRequest.promptSteeringCount = descriptor.promptSteeringCount;
7283
+ activeRequest.promptTriggerText = descriptor.promptTriggerText;
7284
+ }
7285
+
7231
7286
  return queuedRequest;
7232
7287
  };
7233
7288