agentgui 1.0.726 → 1.0.728

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.726",
3
+ "version": "1.0.728",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",
package/server.js CHANGED
@@ -1506,7 +1506,7 @@ const server = http.createServer(async (req, res) => {
1506
1506
  if (messagesMatch) {
1507
1507
  if (req.method === 'GET') {
1508
1508
  const url = new URL(req.url, 'http://localhost');
1509
- const limit = Math.min(parseInt(url.searchParams.get('limit') || '50'), 100);
1509
+ const limit = Math.min(parseInt(url.searchParams.get('limit') || '50'), 500);
1510
1510
  const offset = Math.max(parseInt(url.searchParams.get('offset') || '0'), 0);
1511
1511
  const result = queries.getPaginatedMessages(messagesMatch[1], limit, offset);
1512
1512
  sendJSON(req, res, 200, result);
@@ -880,58 +880,7 @@ class AgentGUIClient {
880
880
  }));
881
881
  const userMsgs = (fullData.messages || []).filter(m => m.role === 'user');
882
882
  if (priorChunks.length > 0) {
883
- const sessionOrder = [];
884
- const sessionGroups = {};
885
- priorChunks.forEach(c => {
886
- if (!sessionGroups[c.sessionId]) { sessionGroups[c.sessionId] = []; sessionOrder.push(c.sessionId); }
887
- sessionGroups[c.sessionId].push(c);
888
- });
889
- const priorFrag = document.createDocumentFragment();
890
- let ui = 0;
891
- sessionOrder.forEach(sid => {
892
- const sList = sessionGroups[sid];
893
- const sStart = sList[0].created_at;
894
- while (ui < userMsgs.length && userMsgs[ui].created_at <= sStart) {
895
- const m = userMsgs[ui++];
896
- const uDiv = document.createElement('div');
897
- uDiv.className = 'message message-user';
898
- uDiv.setAttribute('data-msg-id', m.id);
899
- uDiv.innerHTML = `<div class="message-role">User</div>${this.renderMessageContent(m.content)}<div class="message-timestamp">${new Date(m.created_at).toLocaleString()}</div>`;
900
- priorFrag.appendChild(uDiv);
901
- }
902
- const mDiv = document.createElement('div');
903
- mDiv.className = 'message message-assistant';
904
- mDiv.id = `message-${sid}`;
905
- mDiv.innerHTML = '<div class="message-role">Assistant</div><div class="message-blocks streaming-blocks"></div>';
906
- const bEl = mDiv.querySelector('.message-blocks');
907
- const bFrag = document.createDocumentFragment();
908
- sList.forEach(chunk => {
909
- if (!chunk.block?.type) return;
910
- if (chunk.block.type === 'tool_result') {
911
- const lastInFrag = bFrag.lastElementChild;
912
- if (lastInFrag?.classList?.contains('block-tool-use')) {
913
- this.renderer.mergeResultIntoToolUse(lastInFrag, chunk.block);
914
- return;
915
- }
916
- }
917
- const el = this.renderer.renderBlock(chunk.block, chunk, bFrag);
918
- if (!el) return;
919
- bFrag.appendChild(el);
920
- });
921
- bEl.appendChild(bFrag);
922
- const ts = document.createElement('div'); ts.className = 'message-timestamp'; ts.textContent = new Date(sList[sList.length - 1].created_at).toLocaleString();
923
- mDiv.appendChild(ts);
924
- priorFrag.appendChild(mDiv);
925
- });
926
- while (ui < userMsgs.length) {
927
- const m = userMsgs[ui++];
928
- const uDiv = document.createElement('div');
929
- uDiv.className = 'message message-user';
930
- uDiv.setAttribute('data-msg-id', m.id);
931
- uDiv.innerHTML = `<div class="message-role">User</div>${this.renderMessageContent(m.content)}<div class="message-timestamp">${new Date(m.created_at).toLocaleString()}</div>`;
932
- priorFrag.appendChild(uDiv);
933
- }
934
- messagesEl.appendChild(priorFrag);
883
+ this._renderConversationContent(messagesEl, priorChunks, userMsgs, null);
935
884
  } else {
936
885
  messagesEl.appendChild(this.renderMessagesFragment(fullData.messages || []));
937
886
  }
@@ -955,7 +904,6 @@ class AgentGUIClient {
955
904
  `;
956
905
  messagesEl.appendChild(streamingDiv);
957
906
  } else {
958
- // Reuse existing div - ensure streaming class and single indicator
959
907
  streamingDiv.classList.add('streaming-message');
960
908
  streamingDiv.querySelectorAll('.streaming-indicator').forEach(ind => ind.remove());
961
909
  const indDiv = document.createElement('div');
@@ -2130,12 +2078,75 @@ class AgentGUIClient {
2130
2078
  }
2131
2079
  }
2132
2080
 
2133
- /**
2134
- * Render a single chunk to the output
2135
- */
2081
+ _renderConversationContent(messagesContainer, chunks, userMessages, activeSessionId) {
2082
+ if (!chunks || chunks.length === 0) return;
2083
+ const sessionMap = new Map();
2084
+ for (const chunk of chunks) {
2085
+ if (!sessionMap.has(chunk.sessionId)) sessionMap.set(chunk.sessionId, []);
2086
+ sessionMap.get(chunk.sessionId).push(chunk);
2087
+ }
2088
+ const frag = document.createDocumentFragment();
2089
+ let ui = 0;
2090
+ for (const [sid, list] of sessionMap) {
2091
+ const sessionStart = list[0].created_at;
2092
+ while (ui < userMessages.length && userMessages[ui].created_at <= sessionStart) {
2093
+ const m = userMessages[ui++];
2094
+ const uDiv = document.createElement('div');
2095
+ uDiv.className = 'message message-user';
2096
+ uDiv.setAttribute('data-msg-id', m.id);
2097
+ uDiv.innerHTML = `<div class="message-role">User</div>${this.renderMessageContent(m.content)}<div class="message-timestamp">${new Date(m.created_at).toLocaleString()}</div>`;
2098
+ frag.appendChild(uDiv);
2099
+ }
2100
+ const isActive = sid === activeSessionId;
2101
+ const msgDiv = document.createElement('div');
2102
+ msgDiv.className = `message message-assistant${isActive ? ' streaming-message' : ''}`;
2103
+ msgDiv.id = isActive ? `streaming-${sid}` : `message-${sid}`;
2104
+ msgDiv.innerHTML = '<div class="message-role">Assistant</div><div class="message-blocks streaming-blocks"></div>';
2105
+ const blocksEl = msgDiv.querySelector('.message-blocks');
2106
+ const blockFrag = document.createDocumentFragment();
2107
+ const deferred = [];
2108
+ for (const chunk of list) {
2109
+ if (!chunk.block?.type) continue;
2110
+ if (chunk.block.type === 'tool_result') { deferred.push(chunk); continue; }
2111
+ const el = this.renderer.renderBlock(chunk.block, chunk, blockFrag);
2112
+ if (!el) continue;
2113
+ el.classList.add('block-loaded');
2114
+ blockFrag.appendChild(el);
2115
+ }
2116
+ blocksEl.appendChild(blockFrag);
2117
+ for (const chunk of deferred) {
2118
+ const tid = chunk.block.tool_use_id;
2119
+ const toolUseEl = (tid ? blocksEl.querySelector(`.block-tool-use[data-tool-use-id="${tid}"]`) : null)
2120
+ || (blocksEl.lastElementChild?.classList.contains('block-tool-use') ? blocksEl.lastElementChild : null);
2121
+ if (toolUseEl) this.renderer.mergeResultIntoToolUse(toolUseEl, chunk.block);
2122
+ }
2123
+ if (isActive) {
2124
+ const ind = document.createElement('div');
2125
+ ind.className = 'streaming-indicator';
2126
+ ind.style = 'display:flex;align-items:center;gap:0.5rem;padding:0.5rem 0;color:var(--color-text-secondary);font-size:0.875rem;';
2127
+ ind.innerHTML = '<span class="animate-spin" style="display:inline-block;width:1rem;height:1rem;border:2px solid var(--color-border);border-top-color:var(--color-primary);border-radius:50%;"></span><span class="streaming-indicator-label">Processing...</span>';
2128
+ msgDiv.appendChild(ind);
2129
+ } else {
2130
+ const ts = document.createElement('div');
2131
+ ts.className = 'message-timestamp';
2132
+ ts.textContent = new Date(list[list.length - 1].created_at).toLocaleString();
2133
+ msgDiv.appendChild(ts);
2134
+ }
2135
+ frag.appendChild(msgDiv);
2136
+ }
2137
+ while (ui < userMessages.length) {
2138
+ const m = userMessages[ui++];
2139
+ const uDiv = document.createElement('div');
2140
+ uDiv.className = 'message message-user';
2141
+ uDiv.setAttribute('data-msg-id', m.id);
2142
+ uDiv.innerHTML = `<div class="message-role">User</div>${this.renderMessageContent(m.content)}<div class="message-timestamp">${new Date(m.created_at).toLocaleString()}</div>`;
2143
+ frag.appendChild(uDiv);
2144
+ }
2145
+ messagesContainer.appendChild(frag);
2146
+ }
2147
+
2136
2148
  renderChunk(chunk) {
2137
2149
  if (!chunk || !chunk.block) return;
2138
- // Deduplicate: skip if already rendered via WebSocket streaming_progress
2139
2150
  const seq = chunk.sequence;
2140
2151
  if (seq !== undefined) {
2141
2152
  const seen = (this._renderedSeqs = this._renderedSeqs || {})[chunk.sessionId] || (this._renderedSeqs[chunk.sessionId] = new Set());
@@ -2741,10 +2752,11 @@ class AgentGUIClient {
2741
2752
  return;
2742
2753
  }
2743
2754
  try {
2755
+ const base = window.__BASE_URL || '';
2744
2756
  const [convRes, chunksRes, msgsRes] = await Promise.all([
2745
- fetch(`/gm/api/conversations/${conversationId}`),
2746
- fetch(`/gm/api/conversations/${conversationId}/chunks`),
2747
- fetch(`/gm/api/conversations/${conversationId}/messages?limit=500`)
2757
+ fetch(`${base}/api/conversations/${conversationId}`),
2758
+ fetch(`${base}/api/conversations/${conversationId}/chunks`),
2759
+ fetch(`${base}/api/conversations/${conversationId}/messages?limit=500`)
2748
2760
  ]);
2749
2761
  const convData = await convRes.json();
2750
2762
  const chunksData = await chunksRes.json();
@@ -2834,14 +2846,7 @@ class AgentGUIClient {
2834
2846
  try {
2835
2847
  try {
2836
2848
  await window.wsClient.rpc('conv.full', { id: conversationId, allChunks: true });
2837
- } catch (wsErr) {
2838
- const [chunksRes, msgsRes] = await Promise.all([
2839
- fetch(`/gm/api/conversations/${conversationId}/chunks`),
2840
- fetch(`/gm/api/conversations/${conversationId}/messages?limit=500`)
2841
- ]);
2842
- const chunksData = await chunksRes.json();
2843
- const msgsData = await msgsRes.json();
2844
- }
2849
+ } catch (wsErr) {}
2845
2850
  this.invalidateCache(conversationId);
2846
2851
  await this.loadConversationMessages(conversationId);
2847
2852
  } catch (e) {
@@ -2853,103 +2858,8 @@ class AgentGUIClient {
2853
2858
  }
2854
2859
 
2855
2860
  if (chunks.length > 0) {
2856
- const sessionOrder = [];
2857
- const sessionChunks = {};
2858
- chunks.forEach(chunk => {
2859
- if (!sessionChunks[chunk.sessionId]) {
2860
- sessionChunks[chunk.sessionId] = [];
2861
- sessionOrder.push(chunk.sessionId);
2862
- }
2863
- sessionChunks[chunk.sessionId].push(chunk);
2864
- });
2865
-
2866
- const frag = document.createDocumentFragment();
2867
- let userMsgIdx = 0;
2868
-
2869
- sessionOrder.forEach((sessionId) => {
2870
- const sessionChunkList = sessionChunks[sessionId];
2871
- const sessionStart = sessionChunkList[0].created_at;
2872
-
2873
- while (userMsgIdx < userMessages.length && userMessages[userMsgIdx].created_at <= sessionStart) {
2874
- const msg = userMessages[userMsgIdx];
2875
- const userDiv = document.createElement('div');
2876
- userDiv.className = 'message message-user';
2877
- userDiv.setAttribute('data-msg-id', msg.id);
2878
- userDiv.innerHTML = `
2879
- <div class="message-role">User</div>
2880
- ${this.renderMessageContent(msg.content)}
2881
- <div class="message-timestamp">${new Date(msg.created_at).toLocaleString()}</div>
2882
- `;
2883
- frag.appendChild(userDiv);
2884
- userMsgIdx++;
2885
- }
2886
-
2887
- const isCurrentActiveSession = shouldResumeStreaming && latestSession && latestSession.id === sessionId;
2888
- const messageDiv = document.createElement('div');
2889
- messageDiv.className = `message message-assistant${isCurrentActiveSession ? ' streaming-message' : ''}`;
2890
- messageDiv.id = isCurrentActiveSession ? `streaming-${sessionId}` : `message-${sessionId}`;
2891
- messageDiv.innerHTML = '<div class="message-role">Assistant</div><div class="message-blocks streaming-blocks"></div>';
2892
-
2893
- const blocksEl = messageDiv.querySelector('.message-blocks');
2894
- const blockFrag = document.createDocumentFragment();
2895
- const toolResultBlocks = new Map();
2896
-
2897
- sessionChunkList.forEach(chunk => {
2898
- if (!chunk.block?.type) return;
2899
- if (chunk.block.type === 'tool_result') {
2900
- toolResultBlocks.set(chunk.id, chunk);
2901
- return;
2902
- }
2903
- const element = this.renderer.renderBlock(chunk.block, chunk, blockFrag);
2904
- if (!element) return;
2905
- element.classList.add('block-loaded');
2906
- blockFrag.appendChild(element);
2907
- });
2908
-
2909
- blocksEl.appendChild(blockFrag);
2910
-
2911
- toolResultBlocks.forEach((chunk) => {
2912
- const toolUseId = chunk.block.tool_use_id;
2913
- const toolUseEl = toolUseId
2914
- ? blocksEl.querySelector(`.block-tool-use[data-tool-use-id="${toolUseId}"]`)
2915
- : blocksEl.lastElementChild?.classList?.contains('block-type-tool_use') ? blocksEl.lastElementChild : null;
2916
- if (!toolUseEl) return;
2917
- this.renderer.mergeResultIntoToolUse(toolUseEl, chunk.block);
2918
- });
2919
-
2920
- if (isCurrentActiveSession) {
2921
- const indicatorDiv = document.createElement('div');
2922
- indicatorDiv.className = 'streaming-indicator';
2923
- indicatorDiv.style = 'display:flex;align-items:center;gap:0.5rem;padding:0.5rem 0;color:var(--color-text-secondary);font-size:0.875rem;';
2924
- indicatorDiv.innerHTML = `
2925
- <span class="animate-spin" style="display:inline-block;width:1rem;height:1rem;border:2px solid var(--color-border);border-top-color:var(--color-primary);border-radius:50%;"></span>
2926
- <span class="streaming-indicator-label">Processing...</span>
2927
- `;
2928
- messageDiv.appendChild(indicatorDiv);
2929
- } else {
2930
- const ts = document.createElement('div');
2931
- ts.className = 'message-timestamp';
2932
- ts.textContent = new Date(sessionChunkList[sessionChunkList.length - 1].created_at).toLocaleString();
2933
- messageDiv.appendChild(ts);
2934
- }
2935
-
2936
- frag.appendChild(messageDiv);
2937
- });
2938
-
2939
- while (userMsgIdx < userMessages.length) {
2940
- const msg = userMessages[userMsgIdx];
2941
- const userDiv = document.createElement('div');
2942
- userDiv.className = 'message message-user';
2943
- userDiv.setAttribute('data-msg-id', msg.id);
2944
- userDiv.innerHTML = `
2945
- <div class="message-role">User</div>
2946
- ${this.renderMessageContent(msg.content)}
2947
- <div class="message-timestamp">${new Date(msg.created_at).toLocaleString()}</div>
2948
- `;
2949
- frag.appendChild(userDiv);
2950
- userMsgIdx++;
2951
- }
2952
- if (!convSignal.aborted) messagesEl.appendChild(frag);
2861
+ const activeSessionId = (shouldResumeStreaming && latestSession) ? latestSession.id : null;
2862
+ if (!convSignal.aborted) this._renderConversationContent(messagesEl, chunks, userMessages, activeSessionId);
2953
2863
  } else {
2954
2864
  if (!convSignal.aborted) messagesEl.appendChild(this.renderMessagesFragment(allMessages || []));
2955
2865
  }
@@ -3111,7 +3021,8 @@ class AgentGUIClient {
3111
3021
  limit: 50
3112
3022
  });
3113
3023
  } catch (e) {
3114
- const r = await fetch(`/gm/api/conversations/${conversationId}/messages?limit=50`);
3024
+ const base = window.__BASE_URL || '';
3025
+ const r = await fetch(`${base}/api/conversations/${conversationId}/messages?limit=50`);
3115
3026
  const d = await r.json();
3116
3027
  result = { messages: d.messages || [] };
3117
3028
  }
@@ -3123,7 +3034,8 @@ class AgentGUIClient {
3123
3034
  limit: 500
3124
3035
  });
3125
3036
  } catch (e) {
3126
- const r = await fetch(`/gm/api/conversations/${conversationId}/chunks`);
3037
+ const base = window.__BASE_URL || '';
3038
+ const r = await fetch(`${base}/api/conversations/${conversationId}/chunks`);
3127
3039
  const d = await r.json();
3128
3040
  result = { chunks: d.chunks || [] };
3129
3041
  }