agentgui 1.0.267 → 1.0.268
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/lib/claude-runner.js +190 -0
- package/package.json +1 -1
- package/server.js +13 -0
- package/static/index.html +33 -0
- package/static/js/client.js +14 -2
- package/static/js/streaming-renderer.js +9 -5
package/lib/claude-runner.js
CHANGED
|
@@ -736,6 +736,196 @@ registry.register({
|
|
|
736
736
|
}
|
|
737
737
|
});
|
|
738
738
|
|
|
739
|
+
/**
|
|
740
|
+
* Common ACP protocol handler for all ACP agents
|
|
741
|
+
*/
|
|
742
|
+
function createACPProtocolHandler() {
|
|
743
|
+
return function(message, context) {
|
|
744
|
+
if (!message || typeof message !== 'object') return null;
|
|
745
|
+
|
|
746
|
+
// Handle ACP session/update notifications
|
|
747
|
+
if (message.method === 'session/update') {
|
|
748
|
+
const params = message.params || {};
|
|
749
|
+
const update = params.update || {};
|
|
750
|
+
|
|
751
|
+
// Agent message chunk (text response)
|
|
752
|
+
if (update.sessionUpdate === 'agent_message_chunk' && update.content) {
|
|
753
|
+
let contentBlock;
|
|
754
|
+
|
|
755
|
+
// Handle different content formats
|
|
756
|
+
if (typeof update.content === 'string') {
|
|
757
|
+
contentBlock = { type: 'text', text: update.content };
|
|
758
|
+
} else if (update.content.type === 'text' && update.content.text) {
|
|
759
|
+
contentBlock = update.content;
|
|
760
|
+
} else if (update.content.text) {
|
|
761
|
+
contentBlock = { type: 'text', text: update.content.text };
|
|
762
|
+
} else if (update.content.content) {
|
|
763
|
+
const inner = update.content.content;
|
|
764
|
+
if (typeof inner === 'string') {
|
|
765
|
+
contentBlock = { type: 'text', text: inner };
|
|
766
|
+
} else if (inner.type === 'text' && inner.text) {
|
|
767
|
+
contentBlock = inner;
|
|
768
|
+
} else {
|
|
769
|
+
contentBlock = { type: 'text', text: JSON.stringify(inner) };
|
|
770
|
+
}
|
|
771
|
+
} else {
|
|
772
|
+
contentBlock = { type: 'text', text: JSON.stringify(update.content) };
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
return {
|
|
776
|
+
type: 'assistant',
|
|
777
|
+
message: {
|
|
778
|
+
role: 'assistant',
|
|
779
|
+
content: [contentBlock]
|
|
780
|
+
},
|
|
781
|
+
session_id: params.sessionId
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// Tool call
|
|
786
|
+
if (update.sessionUpdate === 'tool_call') {
|
|
787
|
+
return {
|
|
788
|
+
type: 'assistant',
|
|
789
|
+
message: {
|
|
790
|
+
role: 'assistant',
|
|
791
|
+
content: [{
|
|
792
|
+
type: 'tool_use',
|
|
793
|
+
id: update.toolCallId,
|
|
794
|
+
name: update.title || update.kind || 'tool',
|
|
795
|
+
kind: update.kind || 'other',
|
|
796
|
+
input: update.rawInput || update.input || {}
|
|
797
|
+
}]
|
|
798
|
+
},
|
|
799
|
+
session_id: params.sessionId
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// Tool call update (result) - handle all statuses
|
|
804
|
+
if (update.sessionUpdate === 'tool_call_update') {
|
|
805
|
+
const status = update.status;
|
|
806
|
+
const isError = status === 'failed';
|
|
807
|
+
const isCompleted = status === 'completed';
|
|
808
|
+
|
|
809
|
+
if (!isCompleted && !isError) {
|
|
810
|
+
return {
|
|
811
|
+
type: 'tool_status',
|
|
812
|
+
tool_use_id: update.toolCallId,
|
|
813
|
+
status: status,
|
|
814
|
+
kind: update.kind || 'other',
|
|
815
|
+
locations: update.locations || [],
|
|
816
|
+
session_id: params.sessionId
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
const contentParts = [];
|
|
821
|
+
if (update.content && Array.isArray(update.content)) {
|
|
822
|
+
for (const item of update.content) {
|
|
823
|
+
if (item.type === 'content' && item.content) {
|
|
824
|
+
const innerContent = item.content;
|
|
825
|
+
if (innerContent.type === 'text' && innerContent.text) {
|
|
826
|
+
contentParts.push(innerContent.text);
|
|
827
|
+
} else if (innerContent.type === 'resource' && innerContent.resource) {
|
|
828
|
+
contentParts.push(innerContent.resource.text || JSON.stringify(innerContent.resource));
|
|
829
|
+
} else {
|
|
830
|
+
contentParts.push(JSON.stringify(innerContent));
|
|
831
|
+
}
|
|
832
|
+
} else if (item.type === 'diff') {
|
|
833
|
+
const diffText = item.oldText
|
|
834
|
+
? `--- ${item.path}\n+++ ${item.path}\n${item.oldText}\n---\n${item.newText}`
|
|
835
|
+
: `+++ ${item.path}\n${item.newText}`;
|
|
836
|
+
contentParts.push(diffText);
|
|
837
|
+
} else if (item.type === 'terminal') {
|
|
838
|
+
contentParts.push(`[Terminal: ${item.terminalId}]`);
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
const combinedContent = contentParts.join('\n') || (update.rawOutput ? JSON.stringify(update.rawOutput) : '');
|
|
844
|
+
|
|
845
|
+
return {
|
|
846
|
+
type: 'user',
|
|
847
|
+
message: {
|
|
848
|
+
role: 'user',
|
|
849
|
+
content: [{
|
|
850
|
+
type: 'tool_result',
|
|
851
|
+
tool_use_id: update.toolCallId,
|
|
852
|
+
content: combinedContent,
|
|
853
|
+
is_error: isError
|
|
854
|
+
}]
|
|
855
|
+
},
|
|
856
|
+
session_id: params.sessionId
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// Usage update
|
|
861
|
+
if (update.sessionUpdate === 'usage_update') {
|
|
862
|
+
return {
|
|
863
|
+
type: 'usage',
|
|
864
|
+
usage: {
|
|
865
|
+
used: update.used,
|
|
866
|
+
size: update.size,
|
|
867
|
+
cost: update.cost
|
|
868
|
+
},
|
|
869
|
+
session_id: params.sessionId
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
// Plan update
|
|
874
|
+
if (update.sessionUpdate === 'plan') {
|
|
875
|
+
return {
|
|
876
|
+
type: 'plan',
|
|
877
|
+
entries: update.entries || [],
|
|
878
|
+
session_id: params.sessionId
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
return null;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// Handle prompt response (end of turn)
|
|
886
|
+
if (message.id && message.result && message.result.stopReason) {
|
|
887
|
+
return {
|
|
888
|
+
type: 'result',
|
|
889
|
+
result: '',
|
|
890
|
+
stopReason: message.result.stopReason,
|
|
891
|
+
usage: message.result.usage,
|
|
892
|
+
session_id: context.sessionId
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
if (message.method === 'error' || message.error) {
|
|
897
|
+
return {
|
|
898
|
+
type: 'error',
|
|
899
|
+
error: message.error || message.params || { message: 'Unknown error' }
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
return null;
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
// Handle prompt response (end of turn)
|
|
908
|
+
if (message.id && message.result && message.result.stopReason) {
|
|
909
|
+
return {
|
|
910
|
+
type: 'result',
|
|
911
|
+
result: '',
|
|
912
|
+
stopReason: message.result.stopReason,
|
|
913
|
+
usage: message.result.usage,
|
|
914
|
+
session_id: context.sessionId
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
if (message.method === 'error' || message.error) {
|
|
919
|
+
return {
|
|
920
|
+
type: 'error',
|
|
921
|
+
error: message.error || message.params || { message: 'Unknown error' }
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
return null;
|
|
926
|
+
}
|
|
927
|
+
});
|
|
928
|
+
|
|
739
929
|
/**
|
|
740
930
|
* Common ACP protocol handler for all ACP agents
|
|
741
931
|
*/
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -2821,6 +2821,19 @@ async function processMessageWithStreaming(conversationId, messageId, sessionId,
|
|
|
2821
2821
|
return;
|
|
2822
2822
|
}
|
|
2823
2823
|
|
|
2824
|
+
if (activeExecutions.has(conversationId)) {
|
|
2825
|
+
debugLog(`[stream] Conversation ${conversationId} already has active execution, aborting duplicate`);
|
|
2826
|
+
return;
|
|
2827
|
+
}
|
|
2828
|
+
|
|
2829
|
+
if (rateLimitState.has(conversationId)) {
|
|
2830
|
+
const rlState = rateLimitState.get(conversationId);
|
|
2831
|
+
if (rlState.retryAt > Date.now()) {
|
|
2832
|
+
debugLog(`[stream] Conversation ${conversationId} is in rate limit cooldown, aborting`);
|
|
2833
|
+
return;
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
|
|
2824
2837
|
activeExecutions.set(conversationId, { pid: null, startTime, sessionId, lastActivity: startTime });
|
|
2825
2838
|
queries.setIsStreaming(conversationId, true);
|
|
2826
2839
|
queries.updateSession(sessionId, { status: 'active' });
|
package/static/index.html
CHANGED
|
@@ -970,6 +970,10 @@
|
|
|
970
970
|
details { margin: 0.25rem 0; }
|
|
971
971
|
summary { cursor: pointer; user-select: none; padding: 0.375rem; border-radius: 0.25rem; transition: background-color 0.2s; }
|
|
972
972
|
summary:hover { background-color: var(--color-bg-secondary); }
|
|
973
|
+
.permanently-expanded > summary { cursor: default; }
|
|
974
|
+
.permanently-expanded > summary::before { display: none; }
|
|
975
|
+
.permanently-expanded > summary::-webkit-details-marker { display: none; }
|
|
976
|
+
.permanently-expanded > summary::marker { display: none; content: ''; }
|
|
973
977
|
|
|
974
978
|
/* ===== Folder Browser Modal ===== */
|
|
975
979
|
.folder-modal-overlay { display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.5); z-index:2000; align-items:center; justify-content:center; }
|
|
@@ -2196,6 +2200,35 @@
|
|
|
2196
2200
|
.folded-tool.has-error > .folded-tool-body { border-top-color: #fecaca; }
|
|
2197
2201
|
html.dark .folded-tool.has-error > .folded-tool-body { border-top-color: #7f1d1d; }
|
|
2198
2202
|
|
|
2203
|
+
/* --- Success/Error status icons in header --- */
|
|
2204
|
+
.folded-tool.has-success > .folded-tool-bar .folded-tool-icon::after,
|
|
2205
|
+
.folded-tool.has-error > .folded-tool-bar .folded-tool-icon::after {
|
|
2206
|
+
content: '';
|
|
2207
|
+
display: inline-block;
|
|
2208
|
+
width: 1rem;
|
|
2209
|
+
height: 1rem;
|
|
2210
|
+
margin-left: 0.375rem;
|
|
2211
|
+
background-size: contain;
|
|
2212
|
+
background-repeat: no-repeat;
|
|
2213
|
+
flex-shrink: 0;
|
|
2214
|
+
}
|
|
2215
|
+
.folded-tool.has-success > .folded-tool-bar .folded-tool-icon::after {
|
|
2216
|
+
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 20 20' fill='%2316a34a'%3E%3Cpath fill-rule='evenodd' d='M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z' clip-rule='evenodd'/%3E%3C/svg%3E");
|
|
2217
|
+
}
|
|
2218
|
+
html.dark .folded-tool.has-success > .folded-tool-bar .folded-tool-icon::after {
|
|
2219
|
+
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 20 20' fill='%234ade80'%3E%3Cpath fill-rule='evenodd' d='M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z' clip-rule='evenodd'/%3E%3C/svg%3E");
|
|
2220
|
+
}
|
|
2221
|
+
.folded-tool.has-error > .folded-tool-bar .folded-tool-icon::after {
|
|
2222
|
+
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 20 20' fill='%23ef4444'%3E%3Cpath fill-rule='evenodd' d='M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z' clip-rule='evenodd'/%3E%3C/svg%3E");
|
|
2223
|
+
}
|
|
2224
|
+
html.dark .folded-tool.has-error > .folded-tool-bar .folded-tool-icon::after {
|
|
2225
|
+
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 20 20' fill='%23f87171'%3E%3Cpath fill-rule='evenodd' d='M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z' clip-rule='evenodd'/%3E%3C/svg%3E");
|
|
2226
|
+
}
|
|
2227
|
+
.folded-tool-icon {
|
|
2228
|
+
display: inline-flex;
|
|
2229
|
+
align-items: center;
|
|
2230
|
+
}
|
|
2231
|
+
|
|
2199
2232
|
/* --- Consecutive block joining --- */
|
|
2200
2233
|
.folded-tool + .folded-tool,
|
|
2201
2234
|
.block-tool-use + .block-tool-use {
|
package/static/js/client.js
CHANGED
|
@@ -2305,7 +2305,13 @@ class AgentGUIClient {
|
|
|
2305
2305
|
} else {
|
|
2306
2306
|
this.unlockAgentAndModel();
|
|
2307
2307
|
if (this.ui.agentSelector && cached.conversation.agentType) this.ui.agentSelector.value = cached.conversation.agentType;
|
|
2308
|
-
if (cached.conversation.agentType)
|
|
2308
|
+
if (cached.conversation.agentType) {
|
|
2309
|
+
this.loadModelsForAgent(cached.conversation.agentType).then(() => {
|
|
2310
|
+
if (cached.conversation.model && this.ui.modelSelector) {
|
|
2311
|
+
this.ui.modelSelector.value = cached.conversation.model;
|
|
2312
|
+
}
|
|
2313
|
+
});
|
|
2314
|
+
}
|
|
2309
2315
|
}
|
|
2310
2316
|
this.conversationCache.delete(conversationId);
|
|
2311
2317
|
this.restoreScrollPosition(conversationId);
|
|
@@ -2340,7 +2346,13 @@ class AgentGUIClient {
|
|
|
2340
2346
|
} else {
|
|
2341
2347
|
this.unlockAgentAndModel();
|
|
2342
2348
|
if (this.ui.agentSelector && conversation.agentType) this.ui.agentSelector.value = conversation.agentType;
|
|
2343
|
-
if (conversation.agentType)
|
|
2349
|
+
if (conversation.agentType) {
|
|
2350
|
+
this.loadModelsForAgent(conversation.agentType).then(() => {
|
|
2351
|
+
if (conversation.model && this.ui.modelSelector) {
|
|
2352
|
+
this.ui.modelSelector.value = conversation.model;
|
|
2353
|
+
}
|
|
2354
|
+
});
|
|
2355
|
+
}
|
|
2344
2356
|
}
|
|
2345
2357
|
|
|
2346
2358
|
const chunks = (rawChunks || []).map(chunk => ({
|
|
@@ -519,7 +519,7 @@ class StreamingRenderer {
|
|
|
519
519
|
|
|
520
520
|
const thinking = block.thinking || '';
|
|
521
521
|
div.innerHTML = `
|
|
522
|
-
<details>
|
|
522
|
+
<details open>
|
|
523
523
|
<summary>
|
|
524
524
|
<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/></svg>
|
|
525
525
|
<span>Thinking Process</span>
|
|
@@ -740,7 +740,8 @@ class StreamingRenderer {
|
|
|
740
740
|
const input = block.input || {};
|
|
741
741
|
|
|
742
742
|
const details = document.createElement('details');
|
|
743
|
-
details.className = 'block-tool-use folded-tool';
|
|
743
|
+
details.className = 'block-tool-use folded-tool permanently-expanded';
|
|
744
|
+
details.setAttribute('open', '');
|
|
744
745
|
if (block.id) details.dataset.toolUseId = block.id;
|
|
745
746
|
details.classList.add(this._getBlockTypeClass('tool_use'));
|
|
746
747
|
details.classList.add(this._getToolColorClass(toolName));
|
|
@@ -1296,7 +1297,8 @@ class StreamingRenderer {
|
|
|
1296
1297
|
*/
|
|
1297
1298
|
renderBlockSystem(block, context) {
|
|
1298
1299
|
const details = document.createElement('details');
|
|
1299
|
-
details.className = 'folded-tool folded-tool-info';
|
|
1300
|
+
details.className = 'folded-tool folded-tool-info permanently-expanded';
|
|
1301
|
+
details.setAttribute('open', '');
|
|
1300
1302
|
details.dataset.eventType = 'system';
|
|
1301
1303
|
details.classList.add(this._getBlockTypeClass('system'));
|
|
1302
1304
|
const desc = block.model ? this.escapeHtml(block.model) : 'Session';
|
|
@@ -1333,7 +1335,8 @@ class StreamingRenderer {
|
|
|
1333
1335
|
const statsDesc = [duration, cost, turns ? turns + ' turns' : ''].filter(Boolean).join(' / ');
|
|
1334
1336
|
|
|
1335
1337
|
const details = document.createElement('details');
|
|
1336
|
-
details.className = isError ? 'folded-tool folded-tool-error' : 'folded-tool';
|
|
1338
|
+
details.className = isError ? 'folded-tool folded-tool-error permanently-expanded' : 'folded-tool permanently-expanded';
|
|
1339
|
+
details.setAttribute('open', '');
|
|
1337
1340
|
details.dataset.eventType = 'result';
|
|
1338
1341
|
details.classList.add(this._getBlockTypeClass(isError ? 'error' : 'result'));
|
|
1339
1342
|
|
|
@@ -1766,7 +1769,8 @@ class StreamingRenderer {
|
|
|
1766
1769
|
const msgPreview = message.length > 80 ? message.substring(0, 77) + '...' : message;
|
|
1767
1770
|
|
|
1768
1771
|
const details = document.createElement('details');
|
|
1769
|
-
details.className = 'folded-tool folded-tool-error';
|
|
1772
|
+
details.className = 'folded-tool folded-tool-error permanently-expanded';
|
|
1773
|
+
details.setAttribute('open', '');
|
|
1770
1774
|
details.dataset.eventId = event.id || '';
|
|
1771
1775
|
details.dataset.eventType = 'error';
|
|
1772
1776
|
const summary = document.createElement('summary');
|