@symerian/symi 2.0.10 → 2.0.12

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.
Files changed (32) hide show
  1. package/dist/{audio-preflight-B8ffbICW.js → audio-preflight-Cq4C-m27.js} +4 -4
  2. package/dist/{audio-preflight-DRQD_nt1.js → audio-preflight-DbUFnPX1.js} +4 -4
  3. package/dist/build-info.json +3 -3
  4. package/dist/bundled/boot-md/handler.js +6 -6
  5. package/dist/bundled/session-memory/handler.js +6 -6
  6. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  7. package/dist/{chrome-LmEyZdbC.js → chrome-BATLK3yK.js} +7 -7
  8. package/dist/{chrome-B_zrSLce.js → chrome-h6BnL8Lp.js} +7 -7
  9. package/dist/control-ui/css/style.css +199 -0
  10. package/dist/control-ui/index.html +19 -0
  11. package/dist/control-ui/js/app.js +34 -0
  12. package/dist/control-ui/js/render.js +217 -1
  13. package/dist/control-ui/vendor/highlight.min.js +2518 -0
  14. package/dist/control-ui/vendor/marked.min.js +69 -0
  15. package/dist/daemon-cli.js +6 -6
  16. package/dist/{deliver-CkjSfucB.js → deliver-CZF9f8aC.js} +1 -1
  17. package/dist/{deliver-B3UoBZdC.js → deliver-DD3gs9SF.js} +1 -1
  18. package/dist/extensionAPI.js +6 -6
  19. package/dist/{image-CSeAnozE.js → image-DOnOTocl.js} +1 -1
  20. package/dist/{image-RFofsrof.js → image-RLbZ3RUn.js} +1 -1
  21. package/dist/llm-slug-generator.js +6 -6
  22. package/dist/{pi-embedded-9wEA_0mu.js → pi-embedded-BvCoZBNg.js} +16 -16
  23. package/dist/{pi-embedded-BjzaB3CT.js → pi-embedded-ZzUH4ioO.js} +16 -16
  24. package/dist/{pi-embedded-helpers-BmYZe8o8.js → pi-embedded-helpers--yFTAWwW.js} +4 -4
  25. package/dist/{pi-embedded-helpers-kB5lBgXk.js → pi-embedded-helpers-x8rJur4F.js} +4 -4
  26. package/dist/{pw-ai-CAkn033M.js → pw-ai-CCt1nIO-.js} +1 -1
  27. package/dist/{pw-ai-s-d46DCX.js → pw-ai-C_C5as1t.js} +1 -1
  28. package/dist/{runner-DOvsNiYz.js → runner-DjHRFXSI.js} +1 -1
  29. package/dist/{runner-CJJY2r19.js → runner-uDZlTCm2.js} +1 -1
  30. package/dist/{web-BKQnrqo-.js → web-0bP0TLM2.js} +6 -6
  31. package/dist/{web-CAnxcgBD.js → web-G0LUda_q.js} +6 -6
  32. package/package.json +1 -1
@@ -497,6 +497,216 @@ function formatTime(ts) {
497
497
  // Expose renderBlock for use in app.js streaming finalization
498
498
  window.renderBlock = renderBlock;
499
499
 
500
+ // ── Reasoning Panel — append a block ─────────────────────────────────
501
+ window.appendToReasoningPanel = function (block) {
502
+ const feed = document.getElementById("reasoning-feed");
503
+ if (!feed) {
504
+ return;
505
+ }
506
+
507
+ // Remove empty-state placeholder on first real entry
508
+ const empty = document.getElementById("reasoning-empty");
509
+ if (empty) {
510
+ empty.remove();
511
+ }
512
+
513
+ const entry = document.createElement("div");
514
+ entry.className = "reasoning-entry";
515
+
516
+ switch (block.type) {
517
+ // ── Thinking block ──────────────────────────────────────────────
518
+ case "thinking": {
519
+ const text = (block.thinking ?? "").trim();
520
+ if (!text) {
521
+ return;
522
+ }
523
+ entry.innerHTML = `
524
+ <div class="reasoning-entry-header">
525
+ <span class="reasoning-entry-badge badge-think">◈ THINK</span>
526
+ <span class="reasoning-entry-name">${escHtml(String(text).split("\n")[0].slice(0, 60))}${text.length > 60 ? "…" : ""}</span>
527
+ </div>
528
+ <div class="reasoning-think-body">${escHtml(text)}</div>
529
+ `;
530
+ break;
531
+ }
532
+
533
+ // ── Tool call ───────────────────────────────────────────────────
534
+ case "tool_use": {
535
+ const name = block.name ?? "tool";
536
+ const inputJson = block.input ? JSON.stringify(block.input, null, 2) : "{}";
537
+ // One-line preview: first key=value pair
538
+ let preview = "";
539
+ try {
540
+ const keys = Object.keys(block.input ?? {});
541
+ if (keys.length) {
542
+ const val = String(block.input[keys[0]]).slice(0, 50);
543
+ preview = `${keys[0]}: ${val}${val.length >= 50 ? "…" : ""}`;
544
+ }
545
+ } catch {
546
+ /* ignore */
547
+ }
548
+ entry.innerHTML = `
549
+ <div class="reasoning-entry-header">
550
+ <span class="reasoning-entry-badge badge-tool">${escHtml(toolIcon(name))} TOOL</span>
551
+ <span class="reasoning-entry-name">${escHtml(formatToolName(name))}</span>
552
+ </div>
553
+ ${preview ? `<div class="reasoning-tool-preview">${escHtml(preview)}</div>` : ""}
554
+ <div class="reasoning-tool-detail">${escHtml(inputJson)}</div>
555
+ `;
556
+ // Toggle expand on click
557
+ entry.style.cursor = "pointer";
558
+ entry.addEventListener("click", () => entry.classList.toggle("expanded"));
559
+ break;
560
+ }
561
+
562
+ // ── Tool result ─────────────────────────────────────────────────
563
+ case "tool_result": {
564
+ const content = Array.isArray(block.content)
565
+ ? block.content.map((b) => b.text ?? "").join("\n")
566
+ : String(block.content ?? "");
567
+ const chars = content.length;
568
+ const isError = block.is_error === true;
569
+ entry.innerHTML = `
570
+ <div class="reasoning-entry-header">
571
+ <span class="reasoning-entry-badge badge-result">${isError ? "⚠ ERROR" : "↩ RESULT"}</span>
572
+ <span class="reasoning-entry-name">${chars} chars</span>
573
+ </div>
574
+ <div class="reasoning-result-meta">${escHtml(content.slice(0, 80))}${chars > 80 ? "…" : ""}</div>
575
+ `;
576
+ break;
577
+ }
578
+
579
+ default:
580
+ return; // unknown block — skip
581
+ }
582
+
583
+ feed.appendChild(entry);
584
+ feed.scrollTop = feed.scrollHeight;
585
+ };
586
+
587
+ // ── Reasoning Panel — run separator ──────────────────────────────────
588
+ window.injectReasoningRunSeparator = function () {
589
+ const feed = document.getElementById("reasoning-feed");
590
+ if (!feed) {
591
+ return;
592
+ }
593
+ const empty = document.getElementById("reasoning-empty");
594
+ if (empty) {
595
+ empty.remove();
596
+ }
597
+ const now = new Date();
598
+ const hhmm = now.toLocaleTimeString("en-US", {
599
+ hour: "2-digit",
600
+ minute: "2-digit",
601
+ hour12: false,
602
+ });
603
+ const sep = document.createElement("div");
604
+ sep.className = "reasoning-run-sep";
605
+ sep.innerHTML = `<span class="reasoning-run-sep-label">RUN · ${hhmm}</span>`;
606
+ feed.appendChild(sep);
607
+ feed.scrollTop = feed.scrollHeight;
608
+ };
609
+
610
+ // ── Reasoning Panel — clear ───────────────────────────────────────────
611
+ window.clearReasoningPanel = function () {
612
+ const feed = document.getElementById("reasoning-feed");
613
+ if (!feed) {
614
+ return;
615
+ }
616
+ feed.innerHTML = `
617
+ <div class="reasoning-empty" id="reasoning-empty">
618
+ <div class="reasoning-empty-icon">
619
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
620
+ <circle cx="12" cy="12" r="3"/>
621
+ <path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/>
622
+ </svg>
623
+ </div>
624
+ <div class="reasoning-empty-text">No reasoning yet</div>
625
+ </div>`;
626
+ };
627
+
628
+ // ── Reasoning Panel — live thinking update (streaming) ───────────────
629
+ // Called repeatedly during a run to accumulate thinking text in real-time.
630
+ // Creates a single "live" entry and updates it in-place until finalized.
631
+ let _liveThinkEntry = null;
632
+ let _liveThinkBody = null;
633
+ let _liveThinkBuffer = "";
634
+
635
+ window.openLiveThinking = function () {
636
+ const feed = document.getElementById("reasoning-feed");
637
+ if (!feed) {
638
+ return;
639
+ }
640
+ const empty = document.getElementById("reasoning-empty");
641
+ if (empty) {
642
+ empty.remove();
643
+ }
644
+ _liveThinkBuffer = "";
645
+ const entry = document.createElement("div");
646
+ entry.className = "reasoning-entry";
647
+ entry.id = "reasoning-live-think";
648
+ entry.innerHTML = `
649
+ <div class="reasoning-entry-header">
650
+ <span class="reasoning-entry-badge badge-think">◈ THINK</span>
651
+ <span class="reasoning-entry-name" id="reasoning-live-name">…</span>
652
+ </div>
653
+ <div class="reasoning-think-body" id="reasoning-live-body"></div>
654
+ `;
655
+ feed.appendChild(entry);
656
+ _liveThinkEntry = entry;
657
+ _liveThinkBody = entry.querySelector("#reasoning-live-body");
658
+ feed.scrollTop = feed.scrollHeight;
659
+ };
660
+
661
+ window.updateLiveThinking = function (text) {
662
+ if (!_liveThinkBody) {
663
+ window.openLiveThinking();
664
+ }
665
+ _liveThinkBuffer += text;
666
+ if (_liveThinkBody) {
667
+ _liveThinkBody.textContent = _liveThinkBuffer;
668
+ const feed = document.getElementById("reasoning-feed");
669
+ if (feed) {
670
+ feed.scrollTop = feed.scrollHeight;
671
+ }
672
+ }
673
+ // Update name preview
674
+ const nameEl = _liveThinkEntry?.querySelector("#reasoning-live-name");
675
+ if (nameEl) {
676
+ const firstLine = _liveThinkBuffer.split("\n")[0].slice(0, 60);
677
+ nameEl.textContent = firstLine + (_liveThinkBuffer.length > 60 ? "…" : "");
678
+ }
679
+ };
680
+
681
+ window.closeLiveThinking = function () {
682
+ if (_liveThinkEntry) {
683
+ _liveThinkEntry.removeAttribute("id");
684
+ _liveThinkEntry = null;
685
+ _liveThinkBody = null;
686
+ _liveThinkBuffer = "";
687
+ }
688
+ };
689
+
690
+ // ── Extract thinking text from a content array (for streaming deltas) ─
691
+ window.extractThinkingText = function (content) {
692
+ if (!content) {
693
+ return "";
694
+ }
695
+ if (typeof content === "string") {
696
+ return "";
697
+ }
698
+ if (Array.isArray(content)) {
699
+ return content
700
+ .filter((b) => b?.type === "thinking")
701
+ .map((b) => b.thinking ?? "")
702
+ .join("");
703
+ }
704
+ if (content?.content) {
705
+ return window.extractThinkingText(content.content);
706
+ }
707
+ return "";
708
+ };
709
+
500
710
  // ── Main render function — builds a full message element ──────────────
501
711
  window.renderMessage = function (message) {
502
712
  const { role, content, timestamp } = message;
@@ -523,9 +733,15 @@ window.renderMessage = function (message) {
523
733
  bubble.appendChild(copyBtn);
524
734
  }
525
735
 
526
- // Render each content block
736
+ // Render each content block — route reasoning/tool blocks to the side panel
737
+ const REASONING_TYPES = new Set(["thinking", "tool_use", "tool_result"]);
527
738
  const blocks = Array.isArray(content) ? content : [{ type: "text", text: extractText(content) }];
528
739
  for (const block of blocks) {
740
+ if (!isUser && REASONING_TYPES.has(block.type)) {
741
+ // Route to Reasoning Panel — keep response bubble clean
742
+ window.appendToReasoningPanel(block);
743
+ continue;
744
+ }
529
745
  const el = renderBlock(block);
530
746
  if (el.childNodes.length || el.innerHTML) {
531
747
  bubble.appendChild(el);