Nerdur commited on
Commit
be25425
·
verified ·
1 Parent(s): 3961c2f

Upload 2 files

Browse files
Files changed (1) hide show
  1. index.html +373 -7
index.html CHANGED
@@ -542,6 +542,140 @@
542
  50%, 100% { opacity: 0; }
543
  }
544
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
545
  /* --- EXECUTE_CODE REZULTAT (formatiran prikaz umjesto sirovog JSON-a) --- */
546
  .exec-result {
547
  align-self: stretch;
@@ -627,9 +761,14 @@
627
 
628
  <!-- Header -->
629
  <header>
630
- <div class="app-title">
631
- <i class="fa-solid fa-robot" style="color: var(--primary-color);"></i>
632
- AgentScope AI
 
 
 
 
 
633
  </div>
634
  <div style="display:flex; align-items:center; gap:0.2rem;">
635
  <button class="settings-btn" id="open-mcp" aria-label="MCP Serveri" title="MCP Serveri">
@@ -641,6 +780,25 @@
641
  </div>
642
  </header>
643
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
644
  <!-- Main Chat Area -->
645
  <main id="chat-container">
646
  <div class="message system">Dobrodošao. Odaberi model i unesi API Ključ u postavkama za početak.</div>
@@ -883,7 +1041,15 @@
883
  mcpNewUrl: document.getElementById('mcp-new-url'),
884
  mcpNewHeaderName: document.getElementById('mcp-new-header-name'),
885
  mcpNewHeaderValue: document.getElementById('mcp-new-header-value'),
886
- mcpAddBtn: document.getElementById('mcp-add-btn')
 
 
 
 
 
 
 
 
887
  };
888
 
889
  // --- MCP SERVERI (podrazumijevana lista) ---
@@ -913,8 +1079,13 @@
913
  // Historija razgovora (bez system poruke) - koristi se kao kontekst za API pozive.
914
  // NAPOMENA: nema više hardkodiranog limita na broj poruka - historija raste
915
  // prirodno sa razgovorom (provider/model API sam prijavi grešku ako se pređe kontekst).
 
916
  messages: [],
917
 
 
 
 
 
918
  // MCP serveri (runtime lista, sa statusom konekcije i keširanim tools/list po serveru)
919
  mcpServers: [],
920
 
@@ -1079,6 +1250,7 @@
1079
 
1080
  init() {
1081
  this.loadSettings();
 
1082
  this.mcpInit();
1083
  this.loadModelsIntoSelect(this.config.provider, this.config.apiKey);
1084
  this.bindEvents();
@@ -1436,6 +1608,192 @@
1436
  }
1437
  },
1438
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1439
  bindEvents() {
1440
  // Textarea auto-resize
1441
  UI.userInput.addEventListener('input', function() {
@@ -1454,6 +1812,12 @@
1454
 
1455
  UI.sendBtn.addEventListener('click', () => this.sendMessage());
1456
 
 
 
 
 
 
 
1457
  // File upload (attach button otvara sistemski file picker)
1458
  UI.attachBtn.addEventListener('click', () => UI.fileInput.click());
1459
  UI.fileInput.addEventListener('change', (e) => this.handleFileSelect(e.target.files[0]));
@@ -1876,6 +2240,7 @@ ${code}
1876
  UI.loadingSpinner.style.display = 'none';
1877
  UI.sendIcon.style.display = 'block';
1878
  UI.sendBtn.disabled = UI.userInput.value.trim() === '' && !this.pendingAttachment;
 
1879
  }
1880
  },
1881
 
@@ -2001,9 +2366,10 @@ ${code}
2001
  return JSON.stringify(execResult);
2002
  }
2003
  if (name === 'create_artifact') {
2004
- this.showPreview(args.code || '', args.language || 'html');
2005
- this.addAIMessage(`🎨 Artifact "${args.title || 'bez naziva'}" je kreiran i prikazan u pregledu.\n\n\`\`\`${args.language || 'html'}\n${args.code || ''}\n\`\`\``);
2006
- return 'Artifact je uspješno kreiran i prikazan korisniku u live pregledu.';
 
2007
  }
2008
  if (name.startsWith('mcp__')) {
2009
  const [, serverId, ...rest] = name.split('__');
 
542
  50%, 100% { opacity: 0; }
543
  }
544
 
545
+ /* --- SIDEBAR (istorija razgovora) --- */
546
+ .sidebar-overlay {
547
+ position: fixed;
548
+ inset: 0;
549
+ background: rgba(0, 0, 0, 0.5);
550
+ z-index: 40;
551
+ opacity: 0;
552
+ pointer-events: none;
553
+ transition: opacity 0.25s ease;
554
+ }
555
+
556
+ .sidebar-overlay.open {
557
+ opacity: 1;
558
+ pointer-events: auto;
559
+ }
560
+
561
+ .sidebar {
562
+ position: fixed;
563
+ top: 0;
564
+ left: 0;
565
+ height: 100%;
566
+ height: 100dvh;
567
+ width: min(300px, 82vw);
568
+ background-color: var(--surface-color);
569
+ border-right: 1px solid var(--border-color);
570
+ z-index: 50;
571
+ display: flex;
572
+ flex-direction: column;
573
+ transform: translateX(-100%);
574
+ transition: transform 0.25s ease;
575
+ box-shadow: var(--shadow-md);
576
+ }
577
+
578
+ .sidebar.open {
579
+ transform: translateX(0);
580
+ }
581
+
582
+ .sidebar-header {
583
+ display: flex;
584
+ align-items: center;
585
+ justify-content: space-between;
586
+ padding: 1rem;
587
+ border-bottom: 1px solid var(--border-color);
588
+ flex-shrink: 0;
589
+ }
590
+
591
+ .sidebar-new-chat {
592
+ display: flex;
593
+ align-items: center;
594
+ gap: 0.6rem;
595
+ margin: 0.8rem;
596
+ padding: 0.7rem 0.9rem;
597
+ background-color: var(--input-bg);
598
+ border: 1px solid var(--border-color);
599
+ border-radius: 8px;
600
+ color: var(--text-main);
601
+ font-family: inherit;
602
+ font-size: 0.9rem;
603
+ cursor: pointer;
604
+ transition: border-color 0.2s, color 0.2s;
605
+ flex-shrink: 0;
606
+ }
607
+
608
+ .sidebar-new-chat:hover {
609
+ border-color: var(--primary-color);
610
+ color: var(--primary-color);
611
+ }
612
+
613
+ .sidebar-section-label {
614
+ padding: 0 1rem;
615
+ font-size: 0.72rem;
616
+ text-transform: uppercase;
617
+ letter-spacing: 0.05em;
618
+ color: var(--text-secondary);
619
+ margin-bottom: 0.3rem;
620
+ flex-shrink: 0;
621
+ }
622
+
623
+ .sidebar-chat-list {
624
+ flex: 1;
625
+ overflow-y: auto;
626
+ padding: 0 0.5rem 0.5rem;
627
+ display: flex;
628
+ flex-direction: column;
629
+ gap: 0.15rem;
630
+ }
631
+
632
+ .sidebar-chat-item {
633
+ display: flex;
634
+ align-items: center;
635
+ gap: 0.5rem;
636
+ padding: 0.6rem 0.7rem;
637
+ border-radius: 8px;
638
+ cursor: pointer;
639
+ color: var(--text-main);
640
+ font-size: 0.85rem;
641
+ }
642
+
643
+ .sidebar-chat-item span {
644
+ flex: 1;
645
+ overflow: hidden;
646
+ text-overflow: ellipsis;
647
+ white-space: nowrap;
648
+ }
649
+
650
+ .sidebar-chat-item:hover {
651
+ background-color: var(--surface-hover);
652
+ }
653
+
654
+ .sidebar-chat-item.active {
655
+ background-color: var(--surface-hover);
656
+ color: var(--primary-color);
657
+ }
658
+
659
+ .sidebar-chat-delete {
660
+ background: none;
661
+ border: none;
662
+ color: var(--text-secondary);
663
+ cursor: pointer;
664
+ font-size: 0.8rem;
665
+ padding: 0.25rem 0.4rem;
666
+ border-radius: 4px;
667
+ opacity: 0;
668
+ transition: opacity 0.15s, color 0.15s;
669
+ flex-shrink: 0;
670
+ }
671
+
672
+ .sidebar-chat-item:hover .sidebar-chat-delete {
673
+ opacity: 1;
674
+ }
675
+
676
+ .sidebar-chat-delete:hover {
677
+ color: #ef4444;
678
+ }
679
  /* --- EXECUTE_CODE REZULTAT (formatiran prikaz umjesto sirovog JSON-a) --- */
680
  .exec-result {
681
  align-self: stretch;
 
761
 
762
  <!-- Header -->
763
  <header>
764
+ <div style="display:flex; align-items:center; gap:0.4rem;">
765
+ <button class="settings-btn" id="open-sidebar" aria-label="Meni" title="Meni">
766
+ <i class="fa-solid fa-bars"></i>
767
+ </button>
768
+ <div class="app-title">
769
+ <i class="fa-solid fa-robot" style="color: var(--primary-color);"></i>
770
+ AgentScope AI
771
+ </div>
772
  </div>
773
  <div style="display:flex; align-items:center; gap:0.2rem;">
774
  <button class="settings-btn" id="open-mcp" aria-label="MCP Serveri" title="MCP Serveri">
 
780
  </div>
781
  </header>
782
 
783
+ <!-- Sidebar (istorija razgovora) -->
784
+ <div class="sidebar-overlay" id="sidebar-overlay"></div>
785
+ <aside class="sidebar" id="sidebar">
786
+ <div class="sidebar-header">
787
+ <div class="app-title">
788
+ <i class="fa-solid fa-robot" style="color: var(--primary-color);"></i>
789
+ AgentScope AI
790
+ </div>
791
+ <button class="settings-btn" id="close-sidebar" aria-label="Zatvori meni">
792
+ <i class="fa-solid fa-xmark"></i>
793
+ </button>
794
+ </div>
795
+ <button class="sidebar-new-chat" id="sidebar-new-chat" type="button">
796
+ <i class="fa-solid fa-plus"></i> Novi razgovor
797
+ </button>
798
+ <div class="sidebar-section-label">Razgovori</div>
799
+ <div class="sidebar-chat-list" id="sidebar-chat-list"></div>
800
+ </aside>
801
+
802
  <!-- Main Chat Area -->
803
  <main id="chat-container">
804
  <div class="message system">Dobrodošao. Odaberi model i unesi API Ključ u postavkama za početak.</div>
 
1041
  mcpNewUrl: document.getElementById('mcp-new-url'),
1042
  mcpNewHeaderName: document.getElementById('mcp-new-header-name'),
1043
  mcpNewHeaderValue: document.getElementById('mcp-new-header-value'),
1044
+ mcpAddBtn: document.getElementById('mcp-add-btn'),
1045
+
1046
+ // Sidebar (istorija razgovora)
1047
+ sidebar: document.getElementById('sidebar'),
1048
+ sidebarOverlay: document.getElementById('sidebar-overlay'),
1049
+ openSidebarBtn: document.getElementById('open-sidebar'),
1050
+ closeSidebarBtn: document.getElementById('close-sidebar'),
1051
+ sidebarNewChatBtn: document.getElementById('sidebar-new-chat'),
1052
+ sidebarChatList: document.getElementById('sidebar-chat-list')
1053
  };
1054
 
1055
  // --- MCP SERVERI (podrazumijevana lista) ---
 
1079
  // Historija razgovora (bez system poruke) - koristi se kao kontekst za API pozive.
1080
  // NAPOMENA: nema više hardkodiranog limita na broj poruka - historija raste
1081
  // prirodno sa razgovorom (provider/model API sam prijavi grešku ako se pređe kontekst).
1082
+ // Popunjava se u loadChats() pri pokretanju (iz sačuvanog chata ili novog).
1083
  messages: [],
1084
 
1085
+ // Svi sačuvani razgovori (sidebar istorija) - { id, title, messages, updatedAt }[]
1086
+ chats: [],
1087
+ currentChatId: null,
1088
+
1089
  // MCP serveri (runtime lista, sa statusom konekcije i keširanim tools/list po serveru)
1090
  mcpServers: [],
1091
 
 
1250
 
1251
  init() {
1252
  this.loadSettings();
1253
+ this.loadChats();
1254
  this.mcpInit();
1255
  this.loadModelsIntoSelect(this.config.provider, this.config.apiKey);
1256
  this.bindEvents();
 
1608
  }
1609
  },
1610
 
1611
+ // --- SIDEBAR / ISTORIJA RAZGOVORA ---
1612
+ // Sve u localStorage: 'agentscope_chats' (niz razgovora) i
1613
+ // 'agentscope_current_chat_id' (koji je trenutno otvoren).
1614
+
1615
+ loadChats() {
1616
+ let saved = null;
1617
+ try { saved = JSON.parse(localStorage.getItem('agentscope_chats') || 'null'); } catch (e) { /* ignoriši neispravan JSON */ }
1618
+ this.chats = Array.isArray(saved) ? saved : [];
1619
+
1620
+ const savedCurrentId = localStorage.getItem('agentscope_current_chat_id');
1621
+ const existing = this.chats.find(c => c.id === savedCurrentId);
1622
+
1623
+ if (existing) {
1624
+ this.currentChatId = existing.id;
1625
+ this.messages = existing.messages || [];
1626
+ this.renderChatMessages();
1627
+ } else if (this.chats.length) {
1628
+ this.currentChatId = this.chats[0].id;
1629
+ this.messages = this.chats[0].messages || [];
1630
+ this.renderChatMessages();
1631
+ } else {
1632
+ this.startNewChat(true);
1633
+ }
1634
+ this.renderSidebarChatList();
1635
+ },
1636
+
1637
+ saveChats() {
1638
+ localStorage.setItem('agentscope_chats', JSON.stringify(this.chats));
1639
+ if (this.currentChatId) localStorage.setItem('agentscope_current_chat_id', this.currentChatId);
1640
+ },
1641
+
1642
+ // Snima trenutni this.messages u odgovarajući unos u this.chats. Poziva se
1643
+ // nakon svake razmjene poruka. Naslov razgovora se automatski izvodi iz
1644
+ // prve korisničke poruke (dok god je naslov još uvijek podrazumijevan).
1645
+ persistCurrentChat() {
1646
+ if (!this.currentChatId) return;
1647
+ let chat = this.chats.find(c => c.id === this.currentChatId);
1648
+ if (!chat) {
1649
+ chat = { id: this.currentChatId, title: 'Novi razgovor', messages: [], updatedAt: Date.now() };
1650
+ this.chats.unshift(chat);
1651
+ }
1652
+ chat.messages = this.messages;
1653
+ chat.updatedAt = Date.now();
1654
+ if (!chat.title || chat.title === 'Novi razgovor') {
1655
+ const firstUserMsg = this.messages.find(m => m.role === 'user');
1656
+ if (firstUserMsg) {
1657
+ const text = (this.extractDisplayText(firstUserMsg.content) || '').trim();
1658
+ if (text) chat.title = text.slice(0, 45) + (text.length > 45 ? '…' : '');
1659
+ }
1660
+ }
1661
+ this.chats.sort((a, b) => b.updatedAt - a.updatedAt);
1662
+ this.saveChats();
1663
+ this.renderSidebarChatList();
1664
+ },
1665
+
1666
+ // Kreira nov, prazan razgovor i prebacuje se na njega
1667
+ startNewChat(skipUiReset) {
1668
+ const id = 'chat_' + Date.now() + '_' + Math.random().toString(36).slice(2, 8);
1669
+ const chat = { id, title: 'Novi razgovor', messages: [], updatedAt: Date.now() };
1670
+ this.chats.unshift(chat);
1671
+ this.currentChatId = id;
1672
+ this.messages = [];
1673
+ this.saveChats();
1674
+ this.renderSidebarChatList();
1675
+ if (!skipUiReset) {
1676
+ UI.chatContainer.innerHTML = '<div class="message system">Dobrodošao. Odaberi model i unesi API Ključ u postavkama za početak.</div>';
1677
+ this.closeSidebar();
1678
+ }
1679
+ },
1680
+
1681
+ // Prebacuje se na sačuvani razgovor i ponovo iscrtava poruke iz njegove historije
1682
+ switchChat(id) {
1683
+ if (id === this.currentChatId) { this.closeSidebar(); return; }
1684
+ const chat = this.chats.find(c => c.id === id);
1685
+ if (!chat) return;
1686
+ this.currentChatId = id;
1687
+ this.messages = chat.messages || [];
1688
+ localStorage.setItem('agentscope_current_chat_id', id);
1689
+ this.renderChatMessages();
1690
+ this.renderSidebarChatList();
1691
+ this.closeSidebar();
1692
+ },
1693
+
1694
+ deleteChat(id, event) {
1695
+ if (event) event.stopPropagation();
1696
+ if (!confirm('Obrisati ovaj razgovor? Ovo se ne može poništiti.')) return;
1697
+ this.chats = this.chats.filter(c => c.id !== id);
1698
+ this.saveChats();
1699
+ if (this.currentChatId === id) {
1700
+ if (this.chats.length) {
1701
+ this.switchChat(this.chats[0].id);
1702
+ } else {
1703
+ this.startNewChat();
1704
+ }
1705
+ } else {
1706
+ this.renderSidebarChatList();
1707
+ }
1708
+ },
1709
+
1710
+ // Izvlači tekst za prikaz iz sadržaja poruke (može biti string ili
1711
+ // multimodal niz [{type:'text',...}, {type:'image_url',...}])
1712
+ extractDisplayText(content) {
1713
+ if (typeof content === 'string') return content;
1714
+ if (Array.isArray(content)) {
1715
+ const textPart = content.find(p => p.type === 'text');
1716
+ return textPart ? textPart.text : '[slika]';
1717
+ }
1718
+ return '';
1719
+ },
1720
+
1721
+ // AI poruka renderovana odjednom (bez typewriter efekta) - koristi se pri
1722
+ // ponovnom iscrtavanju sačuvane historije razgovora (nema potrebe za animacijom).
1723
+ addAIMessageInstant(text) {
1724
+ const div = document.createElement('div');
1725
+ div.className = 'message ai';
1726
+ const parts = this.parseMessageParts(text);
1727
+ parts.forEach(part => {
1728
+ if (part.type === 'code') {
1729
+ div.appendChild(this.buildCodeBlockElement(part.lang, part.content));
1730
+ } else if (part.content) {
1731
+ const span = document.createElement('span');
1732
+ span.className = 'msg-text';
1733
+ span.textContent = part.content;
1734
+ div.appendChild(span);
1735
+ }
1736
+ });
1737
+ UI.chatContainer.appendChild(div);
1738
+ },
1739
+
1740
+ // Ponovo iscrtava chat-container na osnovu this.messages. Interne
1741
+ // "vodovodne" poruke (role: 'tool', ili assistant poruke sa tool_calls a
1742
+ // bez sadržaja) se ne prikazuju ponovo - ostaju samo kao API kontekst.
1743
+ renderChatMessages() {
1744
+ UI.chatContainer.innerHTML = '';
1745
+ if (!this.messages.length) {
1746
+ UI.chatContainer.innerHTML = '<div class="message system">Dobrodošao. Odaberi model i unesi API Ključ u postavkama za početak.</div>';
1747
+ return;
1748
+ }
1749
+ this.messages.forEach(msg => {
1750
+ if (msg.role === 'user') {
1751
+ const text = this.extractDisplayText(msg.content);
1752
+ const imagePart = Array.isArray(msg.content) ? msg.content.find(p => p.type === 'image_url') : null;
1753
+ this.addUserMessage(text, imagePart ? { type: 'image', dataUrl: imagePart.image_url.url } : null);
1754
+ } else if (msg.role === 'assistant' && msg.content && msg.content.trim()) {
1755
+ this.addAIMessageInstant(msg.content);
1756
+ }
1757
+ });
1758
+ this.scrollToBottom();
1759
+ },
1760
+
1761
+ renderSidebarChatList() {
1762
+ UI.sidebarChatList.innerHTML = '';
1763
+ this.chats.forEach(chat => {
1764
+ const item = document.createElement('div');
1765
+ item.className = 'sidebar-chat-item' + (chat.id === this.currentChatId ? ' active' : '');
1766
+
1767
+ const icon = document.createElement('i');
1768
+ icon.className = 'fa-regular fa-message';
1769
+ item.appendChild(icon);
1770
+
1771
+ const label = document.createElement('span');
1772
+ label.textContent = chat.title || 'Novi razgovor';
1773
+ item.appendChild(label);
1774
+
1775
+ const delBtn = document.createElement('button');
1776
+ delBtn.className = 'sidebar-chat-delete';
1777
+ delBtn.title = 'Obriši razgovor';
1778
+ delBtn.innerHTML = '<i class="fa-regular fa-trash-can"></i>';
1779
+ delBtn.addEventListener('click', (e) => this.deleteChat(chat.id, e));
1780
+ item.appendChild(delBtn);
1781
+
1782
+ item.addEventListener('click', () => this.switchChat(chat.id));
1783
+ UI.sidebarChatList.appendChild(item);
1784
+ });
1785
+ },
1786
+
1787
+ openSidebar() {
1788
+ UI.sidebar.classList.add('open');
1789
+ UI.sidebarOverlay.classList.add('open');
1790
+ },
1791
+
1792
+ closeSidebar() {
1793
+ UI.sidebar.classList.remove('open');
1794
+ UI.sidebarOverlay.classList.remove('open');
1795
+ },
1796
+
1797
  bindEvents() {
1798
  // Textarea auto-resize
1799
  UI.userInput.addEventListener('input', function() {
 
1812
 
1813
  UI.sendBtn.addEventListener('click', () => this.sendMessage());
1814
 
1815
+ // Sidebar (istorija razgovora)
1816
+ UI.openSidebarBtn.addEventListener('click', () => this.openSidebar());
1817
+ UI.closeSidebarBtn.addEventListener('click', () => this.closeSidebar());
1818
+ UI.sidebarOverlay.addEventListener('click', () => this.closeSidebar());
1819
+ UI.sidebarNewChatBtn.addEventListener('click', () => this.startNewChat());
1820
+
1821
  // File upload (attach button otvara sistemski file picker)
1822
  UI.attachBtn.addEventListener('click', () => UI.fileInput.click());
1823
  UI.fileInput.addEventListener('change', (e) => this.handleFileSelect(e.target.files[0]));
 
2240
  UI.loadingSpinner.style.display = 'none';
2241
  UI.sendIcon.style.display = 'block';
2242
  UI.sendBtn.disabled = UI.userInput.value.trim() === '' && !this.pendingAttachment;
2243
+ this.persistCurrentChat();
2244
  }
2245
  },
2246
 
 
2366
  return JSON.stringify(execResult);
2367
  }
2368
  if (name === 'create_artifact') {
2369
+ // Ne otvaramo preview automatski - samo dodajemo poruku sa code
2370
+ // blokom koji ima dugme "Prikaži" (korisnik sam bira kad da klikne).
2371
+ this.addAIMessage(`🎨 Artifact "${args.title || 'bez naziva'}" je kreiran.\n\n\`\`\`${args.language || 'html'}\n${args.code || ''}\n\`\`\``);
2372
+ return 'Artifact je uspješno kreiran. Korisnik može kliknuti dugme "Prikaži" da ga vidi u live pregledu.';
2373
  }
2374
  if (name.startsWith('mcp__')) {
2375
  const [, serverId, ...rest] = name.split('__');