agentgui 1.0.115 → 1.0.116
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/.prd +0 -0
- package/package.json +1 -1
- package/static/index.html +711 -0
- package/static/js/client.js +32 -3
- package/static/js/streaming-renderer.js +263 -128
package/.prd
ADDED
|
File without changes
|
package/package.json
CHANGED
package/static/index.html
CHANGED
|
@@ -912,6 +912,717 @@
|
|
|
912
912
|
@media (min-width: 769px) and (max-width: 1024px) {
|
|
913
913
|
:root { --sidebar-width: 260px; }
|
|
914
914
|
}
|
|
915
|
+
|
|
916
|
+
/* ===== SVG ICON SIZING (Tailwind utilities not loaded) ===== */
|
|
917
|
+
.block-text svg, .block-code svg, .block-thinking svg,
|
|
918
|
+
.block-tool-use svg, .block-tool-result svg, .block-image svg,
|
|
919
|
+
.block-bash svg, .block-system svg, .block-generic svg,
|
|
920
|
+
.block-error svg, .block-result svg,
|
|
921
|
+
.event-streaming-start svg, .event-streaming-complete svg,
|
|
922
|
+
.event-file-read svg, .event-file-write svg,
|
|
923
|
+
.event-git-status svg, .event-command svg, .event-error svg,
|
|
924
|
+
.event-tool-use svg, .event-generic svg {
|
|
925
|
+
width: 1.25rem;
|
|
926
|
+
height: 1.25rem;
|
|
927
|
+
flex-shrink: 0;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
.icon-sm svg { width: 1rem !important; height: 1rem !important; }
|
|
931
|
+
.icon-lg svg { width: 1.5rem !important; height: 1.5rem !important; }
|
|
932
|
+
|
|
933
|
+
/* ===== STREAMING BLOCK STYLES ===== */
|
|
934
|
+
.block-text {
|
|
935
|
+
margin-bottom: 0.75rem;
|
|
936
|
+
padding: 1rem;
|
|
937
|
+
background: var(--color-bg-primary);
|
|
938
|
+
border-radius: 0.5rem;
|
|
939
|
+
border: 1px solid var(--color-border);
|
|
940
|
+
line-height: 1.7;
|
|
941
|
+
font-size: 0.9rem;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
.block-code {
|
|
945
|
+
margin-bottom: 0.75rem;
|
|
946
|
+
border-radius: 0.5rem;
|
|
947
|
+
overflow: hidden;
|
|
948
|
+
border: 1px solid var(--color-border);
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
.block-code .code-header {
|
|
952
|
+
display: flex;
|
|
953
|
+
align-items: center;
|
|
954
|
+
justify-content: space-between;
|
|
955
|
+
gap: 0.5rem;
|
|
956
|
+
background: #1f2937;
|
|
957
|
+
padding: 0.5rem 1rem;
|
|
958
|
+
border-bottom: 1px solid #374151;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
.block-code .code-header .lang-badge {
|
|
962
|
+
font-size: 0.7rem;
|
|
963
|
+
font-family: 'Monaco','Menlo','Ubuntu Mono', monospace;
|
|
964
|
+
color: #9ca3af;
|
|
965
|
+
text-transform: uppercase;
|
|
966
|
+
letter-spacing: 0.05em;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
.block-code .copy-code-btn {
|
|
970
|
+
background: none;
|
|
971
|
+
border: none;
|
|
972
|
+
color: #9ca3af;
|
|
973
|
+
cursor: pointer;
|
|
974
|
+
padding: 0.25rem;
|
|
975
|
+
border-radius: 0.25rem;
|
|
976
|
+
display: flex;
|
|
977
|
+
align-items: center;
|
|
978
|
+
transition: all 0.15s;
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
.block-code .copy-code-btn:hover { color: #e5e7eb; background: #374151; }
|
|
982
|
+
|
|
983
|
+
.block-code pre {
|
|
984
|
+
margin: 0;
|
|
985
|
+
padding: 1rem;
|
|
986
|
+
background: #111827;
|
|
987
|
+
color: #e5e7eb;
|
|
988
|
+
overflow-x: auto;
|
|
989
|
+
font-size: 0.8rem;
|
|
990
|
+
line-height: 1.5;
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
.block-thinking {
|
|
994
|
+
margin-bottom: 0.75rem;
|
|
995
|
+
border-radius: 0.5rem;
|
|
996
|
+
border: 2px solid #c4b5fd;
|
|
997
|
+
background: #f5f3ff;
|
|
998
|
+
overflow: hidden;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
html.dark .block-thinking { border-color: #5b21b6; background: #1e1033; }
|
|
1002
|
+
|
|
1003
|
+
.block-thinking summary {
|
|
1004
|
+
padding: 0.75rem 1rem;
|
|
1005
|
+
cursor: pointer;
|
|
1006
|
+
display: flex;
|
|
1007
|
+
align-items: center;
|
|
1008
|
+
gap: 0.5rem;
|
|
1009
|
+
font-weight: 600;
|
|
1010
|
+
font-size: 0.85rem;
|
|
1011
|
+
color: #5b21b6;
|
|
1012
|
+
user-select: none;
|
|
1013
|
+
background: none;
|
|
1014
|
+
border-radius: 0;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
html.dark .block-thinking summary { color: #c4b5fd; }
|
|
1018
|
+
.block-thinking summary:hover { background: rgba(139,92,246,0.08); }
|
|
1019
|
+
|
|
1020
|
+
.block-thinking .thinking-content {
|
|
1021
|
+
padding: 0.75rem 1rem;
|
|
1022
|
+
border-top: 1px solid #c4b5fd;
|
|
1023
|
+
font-size: 0.85rem;
|
|
1024
|
+
color: #5b21b6;
|
|
1025
|
+
white-space: pre-wrap;
|
|
1026
|
+
line-height: 1.6;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
html.dark .block-thinking .thinking-content { border-color: #5b21b6; color: #c4b5fd; }
|
|
1030
|
+
|
|
1031
|
+
/* --- Tool Use Block --- */
|
|
1032
|
+
.block-tool-use {
|
|
1033
|
+
margin-bottom: 0.75rem;
|
|
1034
|
+
border-radius: 0.5rem;
|
|
1035
|
+
border: 1px solid #a5f3fc;
|
|
1036
|
+
background: #ecfeff;
|
|
1037
|
+
overflow: hidden;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
html.dark .block-tool-use { border-color: #155e75; background: #0c1a24; }
|
|
1041
|
+
|
|
1042
|
+
.block-tool-use .tool-header {
|
|
1043
|
+
padding: 0.625rem 1rem;
|
|
1044
|
+
border-bottom: 1px solid #a5f3fc;
|
|
1045
|
+
display: flex;
|
|
1046
|
+
align-items: center;
|
|
1047
|
+
gap: 0.5rem;
|
|
1048
|
+
background: #cffafe;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
html.dark .block-tool-use .tool-header { border-color: #155e75; background: #0e2a3a; }
|
|
1052
|
+
|
|
1053
|
+
.block-tool-use .tool-header .tool-icon {
|
|
1054
|
+
display: flex;
|
|
1055
|
+
align-items: center;
|
|
1056
|
+
color: #0891b2;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
html.dark .block-tool-use .tool-header .tool-icon { color: #22d3ee; }
|
|
1060
|
+
|
|
1061
|
+
.block-tool-use .tool-header .tool-name {
|
|
1062
|
+
font-weight: 600;
|
|
1063
|
+
font-size: 0.85rem;
|
|
1064
|
+
color: #155e75;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
html.dark .block-tool-use .tool-header .tool-name { color: #67e8f9; }
|
|
1068
|
+
|
|
1069
|
+
.block-tool-use .tool-header .tool-name code {
|
|
1070
|
+
font-family: 'Monaco','Menlo','Ubuntu Mono', monospace;
|
|
1071
|
+
background: #a5f3fc;
|
|
1072
|
+
padding: 0.125rem 0.5rem;
|
|
1073
|
+
border-radius: 0.25rem;
|
|
1074
|
+
font-size: 0.8rem;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
html.dark .block-tool-use .tool-header .tool-name code { background: #164e63; }
|
|
1078
|
+
|
|
1079
|
+
.block-tool-use .tool-params {
|
|
1080
|
+
padding: 0.75rem 1rem;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
.block-tool-use .tool-params .param-label {
|
|
1084
|
+
font-size: 0.7rem;
|
|
1085
|
+
text-transform: uppercase;
|
|
1086
|
+
letter-spacing: 0.05em;
|
|
1087
|
+
color: #0e7490;
|
|
1088
|
+
font-weight: 600;
|
|
1089
|
+
margin-bottom: 0.375rem;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
html.dark .block-tool-use .tool-params .param-label { color: #22d3ee; }
|
|
1093
|
+
|
|
1094
|
+
/* Tool parameter display styles */
|
|
1095
|
+
.tool-param-file {
|
|
1096
|
+
display: flex;
|
|
1097
|
+
align-items: center;
|
|
1098
|
+
gap: 0.5rem;
|
|
1099
|
+
padding: 0.5rem 0.75rem;
|
|
1100
|
+
background: var(--color-bg-primary);
|
|
1101
|
+
border: 1px solid #a5f3fc;
|
|
1102
|
+
border-radius: 0.375rem;
|
|
1103
|
+
font-family: 'Monaco','Menlo','Ubuntu Mono', monospace;
|
|
1104
|
+
font-size: 0.8rem;
|
|
1105
|
+
color: var(--color-text-primary);
|
|
1106
|
+
overflow-x: auto;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
html.dark .tool-param-file { border-color: #155e75; }
|
|
1110
|
+
|
|
1111
|
+
.tool-param-file .file-icon { color: #0891b2; flex-shrink: 0; font-size: 1rem; }
|
|
1112
|
+
.tool-param-file .file-dir { color: var(--color-text-secondary); }
|
|
1113
|
+
.tool-param-file .file-name { font-weight: 600; color: var(--color-text-primary); }
|
|
1114
|
+
|
|
1115
|
+
.tool-param-command {
|
|
1116
|
+
background: #111827;
|
|
1117
|
+
border-radius: 0.375rem;
|
|
1118
|
+
padding: 0.625rem 0.875rem;
|
|
1119
|
+
font-family: 'Monaco','Menlo','Ubuntu Mono', monospace;
|
|
1120
|
+
font-size: 0.8rem;
|
|
1121
|
+
color: #e5e7eb;
|
|
1122
|
+
overflow-x: auto;
|
|
1123
|
+
display: flex;
|
|
1124
|
+
align-items: flex-start;
|
|
1125
|
+
gap: 0.5rem;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
.tool-param-command .prompt-char { color: #34d399; font-weight: 700; flex-shrink: 0; }
|
|
1129
|
+
.tool-param-command .command-text { white-space: pre-wrap; word-break: break-all; }
|
|
1130
|
+
|
|
1131
|
+
.tool-param-diff {
|
|
1132
|
+
border-radius: 0.375rem;
|
|
1133
|
+
overflow: hidden;
|
|
1134
|
+
border: 1px solid var(--color-border);
|
|
1135
|
+
font-family: 'Monaco','Menlo','Ubuntu Mono', monospace;
|
|
1136
|
+
font-size: 0.75rem;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
.tool-param-diff .diff-header {
|
|
1140
|
+
padding: 0.375rem 0.75rem;
|
|
1141
|
+
background: var(--color-bg-secondary);
|
|
1142
|
+
border-bottom: 1px solid var(--color-border);
|
|
1143
|
+
font-weight: 600;
|
|
1144
|
+
font-size: 0.7rem;
|
|
1145
|
+
text-transform: uppercase;
|
|
1146
|
+
letter-spacing: 0.03em;
|
|
1147
|
+
color: var(--color-text-secondary);
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
.tool-param-diff .diff-old {
|
|
1151
|
+
padding: 0.5rem 0.75rem;
|
|
1152
|
+
background: #fef2f2;
|
|
1153
|
+
color: #991b1b;
|
|
1154
|
+
border-bottom: 1px solid var(--color-border);
|
|
1155
|
+
white-space: pre-wrap;
|
|
1156
|
+
word-break: break-all;
|
|
1157
|
+
max-height: 200px;
|
|
1158
|
+
overflow-y: auto;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
html.dark .tool-param-diff .diff-old { background: #1c0f0f; color: #fca5a5; }
|
|
1162
|
+
|
|
1163
|
+
.tool-param-diff .diff-new {
|
|
1164
|
+
padding: 0.5rem 0.75rem;
|
|
1165
|
+
background: #f0fdf4;
|
|
1166
|
+
color: #166534;
|
|
1167
|
+
white-space: pre-wrap;
|
|
1168
|
+
word-break: break-all;
|
|
1169
|
+
max-height: 200px;
|
|
1170
|
+
overflow-y: auto;
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
html.dark .tool-param-diff .diff-new { background: #0a1f0f; color: #86efac; }
|
|
1174
|
+
|
|
1175
|
+
.tool-param-query {
|
|
1176
|
+
display: flex;
|
|
1177
|
+
align-items: center;
|
|
1178
|
+
gap: 0.5rem;
|
|
1179
|
+
padding: 0.5rem 0.75rem;
|
|
1180
|
+
background: var(--color-bg-primary);
|
|
1181
|
+
border: 1px solid #a5f3fc;
|
|
1182
|
+
border-radius: 0.375rem;
|
|
1183
|
+
font-size: 0.85rem;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
html.dark .tool-param-query { border-color: #155e75; }
|
|
1187
|
+
.tool-param-query .query-icon { flex-shrink: 0; font-size: 1rem; }
|
|
1188
|
+
|
|
1189
|
+
.tool-param-url {
|
|
1190
|
+
display: flex;
|
|
1191
|
+
align-items: center;
|
|
1192
|
+
gap: 0.5rem;
|
|
1193
|
+
padding: 0.5rem 0.75rem;
|
|
1194
|
+
background: var(--color-bg-primary);
|
|
1195
|
+
border: 1px solid #a5f3fc;
|
|
1196
|
+
border-radius: 0.375rem;
|
|
1197
|
+
font-family: 'Monaco','Menlo','Ubuntu Mono', monospace;
|
|
1198
|
+
font-size: 0.8rem;
|
|
1199
|
+
color: #2563eb;
|
|
1200
|
+
word-break: break-all;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
html.dark .tool-param-url { border-color: #155e75; color: #60a5fa; }
|
|
1204
|
+
.tool-param-url .url-icon { flex-shrink: 0; font-size: 1rem; }
|
|
1205
|
+
|
|
1206
|
+
.tool-param-todos {
|
|
1207
|
+
display: flex;
|
|
1208
|
+
flex-direction: column;
|
|
1209
|
+
gap: 0.25rem;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
.tool-param-todos .todo-item {
|
|
1213
|
+
display: flex;
|
|
1214
|
+
align-items: flex-start;
|
|
1215
|
+
gap: 0.5rem;
|
|
1216
|
+
padding: 0.375rem 0.5rem;
|
|
1217
|
+
border-radius: 0.25rem;
|
|
1218
|
+
font-size: 0.8rem;
|
|
1219
|
+
background: var(--color-bg-primary);
|
|
1220
|
+
border: 1px solid var(--color-border);
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
.tool-param-todos .todo-status {
|
|
1224
|
+
flex-shrink: 0;
|
|
1225
|
+
font-size: 0.85rem;
|
|
1226
|
+
margin-top: 0.05rem;
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
.tool-param-todos .todo-text { flex: 1; line-height: 1.4; }
|
|
1230
|
+
|
|
1231
|
+
.tool-param-json {
|
|
1232
|
+
background: var(--color-bg-primary);
|
|
1233
|
+
border: 1px solid #a5f3fc;
|
|
1234
|
+
border-radius: 0.375rem;
|
|
1235
|
+
overflow: hidden;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
html.dark .tool-param-json { border-color: #155e75; }
|
|
1239
|
+
|
|
1240
|
+
.tool-param-json pre {
|
|
1241
|
+
margin: 0;
|
|
1242
|
+
padding: 0.625rem 0.875rem;
|
|
1243
|
+
font-size: 0.75rem;
|
|
1244
|
+
overflow-x: auto;
|
|
1245
|
+
max-height: 200px;
|
|
1246
|
+
overflow-y: auto;
|
|
1247
|
+
white-space: pre-wrap;
|
|
1248
|
+
word-break: break-all;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
.tool-param-content-preview {
|
|
1252
|
+
border-radius: 0.375rem;
|
|
1253
|
+
overflow: hidden;
|
|
1254
|
+
border: 1px solid var(--color-border);
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
.tool-param-content-preview .preview-header {
|
|
1258
|
+
padding: 0.375rem 0.75rem;
|
|
1259
|
+
background: var(--color-bg-secondary);
|
|
1260
|
+
font-size: 0.7rem;
|
|
1261
|
+
font-weight: 600;
|
|
1262
|
+
text-transform: uppercase;
|
|
1263
|
+
letter-spacing: 0.03em;
|
|
1264
|
+
color: var(--color-text-secondary);
|
|
1265
|
+
border-bottom: 1px solid var(--color-border);
|
|
1266
|
+
display: flex;
|
|
1267
|
+
justify-content: space-between;
|
|
1268
|
+
align-items: center;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
.tool-param-content-preview .preview-body {
|
|
1272
|
+
padding: 0.5rem 0.75rem;
|
|
1273
|
+
font-family: 'Monaco','Menlo','Ubuntu Mono', monospace;
|
|
1274
|
+
font-size: 0.75rem;
|
|
1275
|
+
max-height: 200px;
|
|
1276
|
+
overflow-y: auto;
|
|
1277
|
+
white-space: pre-wrap;
|
|
1278
|
+
word-break: break-all;
|
|
1279
|
+
background: var(--color-bg-code);
|
|
1280
|
+
color: #d1d5db;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
.tool-param-content-preview .preview-truncated {
|
|
1284
|
+
padding: 0.25rem 0.75rem;
|
|
1285
|
+
font-size: 0.7rem;
|
|
1286
|
+
color: var(--color-text-secondary);
|
|
1287
|
+
background: var(--color-bg-secondary);
|
|
1288
|
+
text-align: center;
|
|
1289
|
+
border-top: 1px solid var(--color-border);
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
/* --- Tool Result Block --- */
|
|
1293
|
+
.block-tool-result {
|
|
1294
|
+
margin-bottom: 0.75rem;
|
|
1295
|
+
border-radius: 0.5rem;
|
|
1296
|
+
overflow: hidden;
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
.block-tool-result.result-success { border: 1px solid #86efac; background: #f0fdf4; }
|
|
1300
|
+
.block-tool-result.result-error { border: 1px solid #fca5a5; background: #fef2f2; }
|
|
1301
|
+
html.dark .block-tool-result.result-success { border-color: #166534; background: #0a1f0f; }
|
|
1302
|
+
html.dark .block-tool-result.result-error { border-color: #991b1b; background: #1c0f0f; }
|
|
1303
|
+
|
|
1304
|
+
.block-tool-result .result-header {
|
|
1305
|
+
padding: 0.5rem 1rem;
|
|
1306
|
+
display: flex;
|
|
1307
|
+
align-items: center;
|
|
1308
|
+
justify-content: space-between;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
.block-tool-result.result-success .result-header { background: #dcfce7; border-bottom: 1px solid #86efac; }
|
|
1312
|
+
.block-tool-result.result-error .result-header { background: #fee2e2; border-bottom: 1px solid #fca5a5; }
|
|
1313
|
+
html.dark .block-tool-result.result-success .result-header { background: #0f2b1a; border-color: #166534; }
|
|
1314
|
+
html.dark .block-tool-result.result-error .result-header { background: #2c1010; border-color: #991b1b; }
|
|
1315
|
+
|
|
1316
|
+
.block-tool-result .result-header .status-label {
|
|
1317
|
+
display: flex;
|
|
1318
|
+
align-items: center;
|
|
1319
|
+
gap: 0.375rem;
|
|
1320
|
+
font-weight: 600;
|
|
1321
|
+
font-size: 0.8rem;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
.block-tool-result.result-success .status-label { color: #166534; }
|
|
1325
|
+
.block-tool-result.result-error .status-label { color: #991b1b; }
|
|
1326
|
+
html.dark .block-tool-result.result-success .status-label { color: #86efac; }
|
|
1327
|
+
html.dark .block-tool-result.result-error .status-label { color: #fca5a5; }
|
|
1328
|
+
|
|
1329
|
+
.block-tool-result .result-body {
|
|
1330
|
+
padding: 0.625rem 1rem;
|
|
1331
|
+
font-size: 0.8rem;
|
|
1332
|
+
white-space: pre-wrap;
|
|
1333
|
+
word-break: break-all;
|
|
1334
|
+
overflow-x: auto;
|
|
1335
|
+
max-height: 400px;
|
|
1336
|
+
overflow-y: auto;
|
|
1337
|
+
line-height: 1.5;
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
.block-tool-result.result-success .result-body { color: #14532d; }
|
|
1341
|
+
.block-tool-result.result-error .result-body { color: #7f1d1d; }
|
|
1342
|
+
html.dark .block-tool-result.result-success .result-body { color: #bbf7d0; }
|
|
1343
|
+
html.dark .block-tool-result.result-error .result-body { color: #fecaca; }
|
|
1344
|
+
|
|
1345
|
+
.block-tool-result .result-body.collapsed { max-height: 150px; position: relative; }
|
|
1346
|
+
.block-tool-result .result-body.collapsed::after {
|
|
1347
|
+
content: '';
|
|
1348
|
+
position: absolute;
|
|
1349
|
+
bottom: 0;
|
|
1350
|
+
left: 0;
|
|
1351
|
+
right: 0;
|
|
1352
|
+
height: 3rem;
|
|
1353
|
+
background: linear-gradient(transparent, var(--color-bg-primary));
|
|
1354
|
+
pointer-events: none;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
.block-tool-result .expand-btn {
|
|
1358
|
+
display: block;
|
|
1359
|
+
width: 100%;
|
|
1360
|
+
padding: 0.375rem;
|
|
1361
|
+
background: var(--color-bg-secondary);
|
|
1362
|
+
border: none;
|
|
1363
|
+
border-top: 1px solid var(--color-border);
|
|
1364
|
+
cursor: pointer;
|
|
1365
|
+
font-size: 0.75rem;
|
|
1366
|
+
color: var(--color-primary);
|
|
1367
|
+
font-weight: 500;
|
|
1368
|
+
text-align: center;
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
.block-tool-result .expand-btn:hover { background: var(--color-border); }
|
|
1372
|
+
|
|
1373
|
+
.block-tool-result .result-id {
|
|
1374
|
+
font-size: 0.65rem;
|
|
1375
|
+
font-family: 'Monaco','Menlo','Ubuntu Mono', monospace;
|
|
1376
|
+
opacity: 0.6;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
/* --- Result Summary Block --- */
|
|
1380
|
+
.block-result {
|
|
1381
|
+
margin-bottom: 0.75rem;
|
|
1382
|
+
border-radius: 0.5rem;
|
|
1383
|
+
overflow: hidden;
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
.block-result.result-ok {
|
|
1387
|
+
background: linear-gradient(135deg, #ecfdf5, #f0fdf4);
|
|
1388
|
+
border: 1px solid #86efac;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
.block-result.result-err {
|
|
1392
|
+
background: linear-gradient(135deg, #fef2f2, #fff1f2);
|
|
1393
|
+
border: 1px solid #fca5a5;
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
html.dark .block-result.result-ok { background: linear-gradient(135deg, #0a1f0f, #0f2b1a); border-color: #166534; }
|
|
1397
|
+
html.dark .block-result.result-err { background: linear-gradient(135deg, #1c0f0f, #2c1010); border-color: #991b1b; }
|
|
1398
|
+
|
|
1399
|
+
.block-result .result-summary-header {
|
|
1400
|
+
padding: 0.625rem 1rem;
|
|
1401
|
+
display: flex;
|
|
1402
|
+
align-items: center;
|
|
1403
|
+
gap: 0.5rem;
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
.block-result.result-ok .result-summary-header { color: #166534; }
|
|
1407
|
+
.block-result.result-err .result-summary-header { color: #991b1b; }
|
|
1408
|
+
html.dark .block-result.result-ok .result-summary-header { color: #86efac; }
|
|
1409
|
+
html.dark .block-result.result-err .result-summary-header { color: #fca5a5; }
|
|
1410
|
+
|
|
1411
|
+
.block-result .result-summary-header .result-title { font-weight: 700; font-size: 0.9rem; }
|
|
1412
|
+
|
|
1413
|
+
.block-result .result-stats {
|
|
1414
|
+
display: flex;
|
|
1415
|
+
gap: 1.5rem;
|
|
1416
|
+
padding: 0 1rem 0.625rem;
|
|
1417
|
+
font-size: 0.8rem;
|
|
1418
|
+
flex-wrap: wrap;
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
.block-result .result-stat {
|
|
1422
|
+
display: flex;
|
|
1423
|
+
align-items: center;
|
|
1424
|
+
gap: 0.375rem;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
.block-result .result-stat .stat-icon { font-size: 0.9rem; opacity: 0.7; }
|
|
1428
|
+
.block-result .result-stat .stat-value { font-weight: 600; }
|
|
1429
|
+
.block-result .result-stat .stat-label { color: var(--color-text-secondary); font-size: 0.75rem; }
|
|
1430
|
+
|
|
1431
|
+
.block-result .result-content {
|
|
1432
|
+
padding: 0.625rem 1rem;
|
|
1433
|
+
border-top: 1px solid var(--color-border);
|
|
1434
|
+
font-size: 0.85rem;
|
|
1435
|
+
white-space: pre-wrap;
|
|
1436
|
+
word-break: break-word;
|
|
1437
|
+
max-height: 300px;
|
|
1438
|
+
overflow-y: auto;
|
|
1439
|
+
line-height: 1.5;
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
/* --- System Block --- */
|
|
1443
|
+
.block-system {
|
|
1444
|
+
margin-bottom: 0.75rem;
|
|
1445
|
+
border-radius: 0.5rem;
|
|
1446
|
+
border: 1px solid #c7d2fe;
|
|
1447
|
+
background: #eef2ff;
|
|
1448
|
+
overflow: hidden;
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
html.dark .block-system { border-color: #3730a3; background: #15103a; }
|
|
1452
|
+
|
|
1453
|
+
.block-system .system-header {
|
|
1454
|
+
padding: 0.625rem 1rem;
|
|
1455
|
+
background: #e0e7ff;
|
|
1456
|
+
border-bottom: 1px solid #c7d2fe;
|
|
1457
|
+
font-weight: 600;
|
|
1458
|
+
font-size: 0.85rem;
|
|
1459
|
+
color: #3730a3;
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
html.dark .block-system .system-header { background: #1e1b4b; border-color: #3730a3; color: #a5b4fc; }
|
|
1463
|
+
|
|
1464
|
+
.block-system .system-body {
|
|
1465
|
+
padding: 0.75rem 1rem;
|
|
1466
|
+
font-size: 0.8rem;
|
|
1467
|
+
color: #3730a3;
|
|
1468
|
+
display: flex;
|
|
1469
|
+
flex-direction: column;
|
|
1470
|
+
gap: 0.375rem;
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
html.dark .block-system .system-body { color: #c7d2fe; }
|
|
1474
|
+
|
|
1475
|
+
.block-system .system-body .sys-field { display: flex; align-items: baseline; gap: 0.5rem; }
|
|
1476
|
+
.block-system .system-body .sys-label { font-weight: 600; flex-shrink: 0; min-width: 5rem; }
|
|
1477
|
+
.block-system .system-body .sys-value { font-family: 'Monaco','Menlo','Ubuntu Mono', monospace; font-size: 0.75rem; }
|
|
1478
|
+
.block-system .system-body .sys-value code { background: #c7d2fe; padding: 0.0625rem 0.375rem; border-radius: 0.25rem; }
|
|
1479
|
+
html.dark .block-system .system-body .sys-value code { background: #312e81; }
|
|
1480
|
+
|
|
1481
|
+
.block-system .tools-list {
|
|
1482
|
+
display: flex;
|
|
1483
|
+
flex-wrap: wrap;
|
|
1484
|
+
gap: 0.25rem;
|
|
1485
|
+
margin-top: 0.25rem;
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
.block-system .tools-list .tool-badge {
|
|
1489
|
+
display: inline-block;
|
|
1490
|
+
padding: 0.125rem 0.5rem;
|
|
1491
|
+
background: #c7d2fe;
|
|
1492
|
+
color: #3730a3;
|
|
1493
|
+
border-radius: 1rem;
|
|
1494
|
+
font-size: 0.65rem;
|
|
1495
|
+
font-weight: 500;
|
|
1496
|
+
font-family: 'Monaco','Menlo','Ubuntu Mono', monospace;
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
html.dark .block-system .tools-list .tool-badge { background: #312e81; color: #a5b4fc; }
|
|
1500
|
+
|
|
1501
|
+
/* --- Bash Block --- */
|
|
1502
|
+
.block-bash {
|
|
1503
|
+
margin-bottom: 0.75rem;
|
|
1504
|
+
border-radius: 0.5rem;
|
|
1505
|
+
overflow: hidden;
|
|
1506
|
+
border: 1px solid #374151;
|
|
1507
|
+
background: #111827;
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
.block-bash .bash-command {
|
|
1511
|
+
padding: 0.625rem 1rem;
|
|
1512
|
+
border-bottom: 1px solid #374151;
|
|
1513
|
+
display: flex;
|
|
1514
|
+
align-items: flex-start;
|
|
1515
|
+
gap: 0.5rem;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
.block-bash .bash-command .prompt { color: #34d399; font-weight: 700; flex-shrink: 0; }
|
|
1519
|
+
.block-bash .bash-command code {
|
|
1520
|
+
font-family: 'Monaco','Menlo','Ubuntu Mono', monospace;
|
|
1521
|
+
color: #e5e7eb;
|
|
1522
|
+
font-size: 0.8rem;
|
|
1523
|
+
overflow-x: auto;
|
|
1524
|
+
flex: 1;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
.block-bash .bash-output {
|
|
1528
|
+
padding: 0.625rem 1rem;
|
|
1529
|
+
color: #9ca3af;
|
|
1530
|
+
font-size: 0.75rem;
|
|
1531
|
+
overflow-x: auto;
|
|
1532
|
+
white-space: pre-wrap;
|
|
1533
|
+
max-height: 300px;
|
|
1534
|
+
overflow-y: auto;
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
/* --- Generic Block --- */
|
|
1538
|
+
.block-generic {
|
|
1539
|
+
margin-bottom: 0.75rem;
|
|
1540
|
+
padding: 0.75rem 1rem;
|
|
1541
|
+
border-radius: 0.5rem;
|
|
1542
|
+
border: 1px solid var(--color-border);
|
|
1543
|
+
background: var(--color-bg-secondary);
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
.block-generic .generic-type {
|
|
1547
|
+
font-size: 0.7rem;
|
|
1548
|
+
text-transform: uppercase;
|
|
1549
|
+
letter-spacing: 0.05em;
|
|
1550
|
+
color: var(--color-text-secondary);
|
|
1551
|
+
font-weight: 600;
|
|
1552
|
+
margin-bottom: 0.375rem;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
.block-generic .generic-fields {
|
|
1556
|
+
display: flex;
|
|
1557
|
+
flex-direction: column;
|
|
1558
|
+
gap: 0.25rem;
|
|
1559
|
+
font-size: 0.8rem;
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
.block-generic .generic-field {
|
|
1563
|
+
display: flex;
|
|
1564
|
+
gap: 0.5rem;
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
.block-generic .generic-field .field-key {
|
|
1568
|
+
font-weight: 600;
|
|
1569
|
+
color: var(--color-text-secondary);
|
|
1570
|
+
flex-shrink: 0;
|
|
1571
|
+
font-family: 'Monaco','Menlo','Ubuntu Mono', monospace;
|
|
1572
|
+
font-size: 0.75rem;
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
.block-generic .generic-field .field-value {
|
|
1576
|
+
font-family: 'Monaco','Menlo','Ubuntu Mono', monospace;
|
|
1577
|
+
font-size: 0.75rem;
|
|
1578
|
+
word-break: break-all;
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
/* --- Error Block --- */
|
|
1582
|
+
.block-error {
|
|
1583
|
+
margin-bottom: 0.75rem;
|
|
1584
|
+
padding: 0.75rem 1rem;
|
|
1585
|
+
border-radius: 0.5rem;
|
|
1586
|
+
border: 1px solid #fca5a5;
|
|
1587
|
+
background: #fef2f2;
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
html.dark .block-error { border-color: #991b1b; background: #1c0f0f; }
|
|
1591
|
+
|
|
1592
|
+
/* --- Image Block --- */
|
|
1593
|
+
.block-image {
|
|
1594
|
+
margin-bottom: 0.75rem;
|
|
1595
|
+
border-radius: 0.5rem;
|
|
1596
|
+
overflow: hidden;
|
|
1597
|
+
border: 1px solid var(--color-border);
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
.block-image img { max-width: 100%; height: auto; max-height: 24rem; object-fit: contain; display: block; }
|
|
1601
|
+
.block-image .image-caption { padding: 0.5rem 0.75rem; background: var(--color-bg-secondary); font-size: 0.8rem; color: var(--color-text-secondary); }
|
|
1602
|
+
|
|
1603
|
+
/* ===== STREAMING EVENTS ===== */
|
|
1604
|
+
.event-streaming-start {
|
|
1605
|
+
margin-bottom: 0.75rem;
|
|
1606
|
+
padding: 0.75rem 1rem;
|
|
1607
|
+
background: #eff6ff;
|
|
1608
|
+
border: 1px solid #bfdbfe;
|
|
1609
|
+
border-radius: 0.5rem;
|
|
1610
|
+
display: flex;
|
|
1611
|
+
align-items: center;
|
|
1612
|
+
gap: 0.625rem;
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
html.dark .event-streaming-start { background: #0c1a2e; border-color: #1e40af; }
|
|
1616
|
+
|
|
1617
|
+
.event-streaming-complete {
|
|
1618
|
+
margin-bottom: 0.75rem;
|
|
1619
|
+
padding: 0.75rem 1rem;
|
|
1620
|
+
background: linear-gradient(135deg, #ecfdf5, #f0fdf4);
|
|
1621
|
+
border: 1px solid #86efac;
|
|
1622
|
+
border-radius: 0.5rem;
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
html.dark .event-streaming-complete { background: linear-gradient(135deg, #0a1f0f, #0f2b1a); border-color: #166534; }
|
|
915
1626
|
</style>
|
|
916
1627
|
</head>
|
|
917
1628
|
<body>
|
package/static/js/client.js
CHANGED
|
@@ -468,7 +468,15 @@ class AgentGUIClient {
|
|
|
468
468
|
return this.escapeHtml(part.content);
|
|
469
469
|
}).join('');
|
|
470
470
|
}
|
|
471
|
-
|
|
471
|
+
// Fallback for unknown block types: show formatted key-value pairs
|
|
472
|
+
const fieldsHtml = Object.entries(block)
|
|
473
|
+
.filter(([key]) => key !== 'type')
|
|
474
|
+
.map(([key, value]) => {
|
|
475
|
+
let displayValue = typeof value === 'string' ? value : JSON.stringify(value);
|
|
476
|
+
if (displayValue.length > 100) displayValue = displayValue.substring(0, 100) + '...';
|
|
477
|
+
return `<div style="font-size:0.75rem;margin-bottom:0.25rem"><span style="font-weight:600">${this.escapeHtml(key)}:</span> <code>${this.escapeHtml(displayValue)}</code></div>`;
|
|
478
|
+
}).join('');
|
|
479
|
+
return `<div style="padding:0.5rem;background:var(--color-bg-secondary);border-radius:0.375rem;border:1px solid var(--color-border)"><div style="font-size:0.7rem;font-weight:600;text-transform:uppercase;margin-bottom:0.25rem">${this.escapeHtml(block.type)}</div>${fieldsHtml}</div>`;
|
|
472
480
|
}
|
|
473
481
|
|
|
474
482
|
scrollToBottom() {
|
|
@@ -708,7 +716,17 @@ class AgentGUIClient {
|
|
|
708
716
|
html += '</div>';
|
|
709
717
|
return html;
|
|
710
718
|
} else {
|
|
711
|
-
|
|
719
|
+
// Fallback for non-array content: format as key-value pairs
|
|
720
|
+
if (typeof content === 'object' && content !== null) {
|
|
721
|
+
const fieldsHtml = Object.entries(content)
|
|
722
|
+
.map(([key, value]) => {
|
|
723
|
+
let displayValue = typeof value === 'string' ? value : JSON.stringify(value);
|
|
724
|
+
if (displayValue.length > 150) displayValue = displayValue.substring(0, 150) + '...';
|
|
725
|
+
return `<div style="font-size:0.8rem;margin-bottom:0.375rem"><span style="font-weight:600">${this.escapeHtml(key)}:</span> <code style="background:var(--color-bg-secondary);padding:0.125rem 0.25rem;border-radius:0.25rem">${this.escapeHtml(displayValue)}</code></div>`;
|
|
726
|
+
}).join('');
|
|
727
|
+
return `<div class="message-text" style="background:var(--color-bg-secondary);padding:0.75rem;border-radius:0.375rem">${fieldsHtml}</div>`;
|
|
728
|
+
}
|
|
729
|
+
return `<div class="message-text">${this.escapeHtml(String(content))}</div>`;
|
|
712
730
|
}
|
|
713
731
|
}
|
|
714
732
|
|
|
@@ -1223,7 +1241,18 @@ class AgentGUIClient {
|
|
|
1223
1241
|
}
|
|
1224
1242
|
contentHtml += '</div>';
|
|
1225
1243
|
} else {
|
|
1226
|
-
|
|
1244
|
+
// Fallback for non-array msg.content: format as key-value pairs
|
|
1245
|
+
if (typeof msg.content === 'object' && msg.content !== null) {
|
|
1246
|
+
const fieldsHtml = Object.entries(msg.content)
|
|
1247
|
+
.map(([key, value]) => {
|
|
1248
|
+
let displayValue = typeof value === 'string' ? value : JSON.stringify(value);
|
|
1249
|
+
if (displayValue.length > 150) displayValue = displayValue.substring(0, 150) + '...';
|
|
1250
|
+
return `<div style="font-size:0.8rem;margin-bottom:0.375rem"><span style="font-weight:600">${this.escapeHtml(key)}:</span> <code style="background:var(--color-bg-secondary);padding:0.125rem 0.25rem;border-radius:0.25rem">${this.escapeHtml(displayValue)}</code></div>`;
|
|
1251
|
+
}).join('');
|
|
1252
|
+
contentHtml = `<div class="message-text" style="background:var(--color-bg-secondary);padding:0.75rem;border-radius:0.375rem">${fieldsHtml}</div>`;
|
|
1253
|
+
} else {
|
|
1254
|
+
contentHtml = `<div class="message-text">${this.escapeHtml(String(msg.content))}</div>`;
|
|
1255
|
+
}
|
|
1227
1256
|
}
|
|
1228
1257
|
|
|
1229
1258
|
return `
|
|
@@ -373,6 +373,8 @@ class StreamingRenderer {
|
|
|
373
373
|
return this.renderBlockBash(block, context);
|
|
374
374
|
case 'system':
|
|
375
375
|
return this.renderBlockSystem(block, context);
|
|
376
|
+
case 'result':
|
|
377
|
+
return this.renderBlockResult(block, context);
|
|
376
378
|
default:
|
|
377
379
|
return this.renderBlockGeneric(block, context);
|
|
378
380
|
}
|
|
@@ -387,11 +389,9 @@ class StreamingRenderer {
|
|
|
387
389
|
*/
|
|
388
390
|
renderBlockText(block, context) {
|
|
389
391
|
const div = document.createElement('div');
|
|
390
|
-
div.className = 'block-text
|
|
392
|
+
div.className = 'block-text';
|
|
391
393
|
|
|
392
394
|
const text = block.text || '';
|
|
393
|
-
|
|
394
|
-
// Parse markdown code blocks and links
|
|
395
395
|
const html = this.parseAndRenderMarkdown(text);
|
|
396
396
|
div.innerHTML = html;
|
|
397
397
|
|
|
@@ -428,36 +428,30 @@ class StreamingRenderer {
|
|
|
428
428
|
*/
|
|
429
429
|
renderBlockCode(block, context) {
|
|
430
430
|
const div = document.createElement('div');
|
|
431
|
-
div.className = 'block-code
|
|
431
|
+
div.className = 'block-code';
|
|
432
432
|
|
|
433
433
|
const code = block.code || '';
|
|
434
434
|
const language = (block.language || 'plaintext').toLowerCase();
|
|
435
435
|
|
|
436
|
-
// Create header with language badge
|
|
437
436
|
const header = document.createElement('div');
|
|
438
|
-
header.className = '
|
|
437
|
+
header.className = 'code-header';
|
|
439
438
|
header.innerHTML = `
|
|
440
|
-
<span class="
|
|
441
|
-
<button class="copy-code-btn
|
|
442
|
-
<svg
|
|
443
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
|
|
444
|
-
</svg>
|
|
439
|
+
<span class="lang-badge">${this.escapeHtml(language)}</span>
|
|
440
|
+
<button class="copy-code-btn" title="Copy code">
|
|
441
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg>
|
|
445
442
|
</button>
|
|
446
443
|
`;
|
|
447
444
|
|
|
448
|
-
// Add copy functionality
|
|
449
445
|
const copyBtn = header.querySelector('.copy-code-btn');
|
|
450
446
|
copyBtn.addEventListener('click', () => {
|
|
451
447
|
navigator.clipboard.writeText(code).then(() => {
|
|
452
|
-
const
|
|
453
|
-
copyBtn.innerHTML = '<svg
|
|
454
|
-
setTimeout(() => { copyBtn.innerHTML =
|
|
448
|
+
const orig = copyBtn.innerHTML;
|
|
449
|
+
copyBtn.innerHTML = '<svg viewBox="0 0 20 20" fill="#34d399"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/></svg>';
|
|
450
|
+
setTimeout(() => { copyBtn.innerHTML = orig; }, 2000);
|
|
455
451
|
});
|
|
456
452
|
});
|
|
457
453
|
|
|
458
|
-
// Create code container
|
|
459
454
|
const codeContainer = document.createElement('pre');
|
|
460
|
-
codeContainer.className = 'bg-gray-900 dark:bg-gray-950 text-gray-100 p-4 overflow-x-auto';
|
|
461
455
|
codeContainer.innerHTML = `<code class="language-${this.escapeHtml(language)}">${this.escapeHtml(code)}</code>`;
|
|
462
456
|
|
|
463
457
|
div.appendChild(header);
|
|
@@ -471,20 +465,16 @@ class StreamingRenderer {
|
|
|
471
465
|
*/
|
|
472
466
|
renderBlockThinking(block, context) {
|
|
473
467
|
const div = document.createElement('div');
|
|
474
|
-
div.className = 'block-thinking
|
|
468
|
+
div.className = 'block-thinking';
|
|
475
469
|
|
|
476
470
|
const thinking = block.thinking || '';
|
|
477
471
|
div.innerHTML = `
|
|
478
|
-
<details
|
|
479
|
-
<summary
|
|
480
|
-
<svg
|
|
481
|
-
|
|
482
|
-
</svg>
|
|
483
|
-
<span>Claude's Thinking Process</span>
|
|
472
|
+
<details>
|
|
473
|
+
<summary>
|
|
474
|
+
<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>
|
|
475
|
+
<span>Thinking Process</span>
|
|
484
476
|
</summary>
|
|
485
|
-
<div class="
|
|
486
|
-
${this.escapeHtml(thinking)}
|
|
487
|
-
</div>
|
|
477
|
+
<div class="thinking-content">${this.escapeHtml(thinking)}</div>
|
|
488
478
|
</details>
|
|
489
479
|
`;
|
|
490
480
|
|
|
@@ -492,69 +482,170 @@ class StreamingRenderer {
|
|
|
492
482
|
}
|
|
493
483
|
|
|
494
484
|
/**
|
|
495
|
-
*
|
|
485
|
+
* Get a tool-specific icon SVG string
|
|
486
|
+
*/
|
|
487
|
+
getToolIcon(toolName) {
|
|
488
|
+
const icons = {
|
|
489
|
+
Read: '<svg viewBox="0 0 20 20" fill="currentColor"><path d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4z"/></svg>',
|
|
490
|
+
Write: '<svg viewBox="0 0 20 20" fill="currentColor"><path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z"/></svg>',
|
|
491
|
+
Edit: '<svg viewBox="0 0 20 20" fill="currentColor"><path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"/><path fill-rule="evenodd" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" clip-rule="evenodd"/></svg>',
|
|
492
|
+
Bash: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M2 5a2 2 0 012-2h12a2 2 0 012 2v10a2 2 0 01-2 2H4a2 2 0 01-2-2V5zm3.293 1.293a1 1 0 011.414 0l3 3a1 1 0 010 1.414l-3 3a1 1 0 01-1.414-1.414L7.586 10 5.293 7.707a1 1 0 010-1.414zM11 12a1 1 0 100 2h3a1 1 0 100-2h-3z" clip-rule="evenodd"/></svg>',
|
|
493
|
+
Glob: '<svg viewBox="0 0 20 20" fill="currentColor"><path d="M2 6a2 2 0 012-2h5l2 2h5a2 2 0 012 2v6a2 2 0 01-2 2H4a2 2 0 01-2-2V6z"/></svg>',
|
|
494
|
+
Grep: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd"/></svg>',
|
|
495
|
+
WebFetch: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM4.332 8.027a6.012 6.012 0 011.912-2.706C6.512 5.73 6.974 6 7.5 6A1.5 1.5 0 019 7.5V8a2 2 0 004 0 2 2 0 012 2v1a2 2 0 01-2 2 2 2 0 01-2 2v.5a6.003 6.003 0 01-6.668-7.473z" clip-rule="evenodd"/></svg>',
|
|
496
|
+
WebSearch: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd"/></svg>',
|
|
497
|
+
TodoWrite: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 011 1v3.586l1.293-1.293a1 1 0 111.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 111.414-1.414L6 11.586V8a1 1 0 011-1z" clip-rule="evenodd"/></svg>',
|
|
498
|
+
Task: '<svg viewBox="0 0 20 20" fill="currentColor"><path d="M9 2a1 1 0 000 2h2a1 1 0 100-2H9z"/><path fill-rule="evenodd" d="M4 5a2 2 0 012-2 3 3 0 003 3h2a3 3 0 003-3 2 2 0 012 2v11a2 2 0 01-2 2H6a2 2 0 01-2-2V5zm3 4a1 1 0 000 2h.01a1 1 0 100-2H7zm3 0a1 1 0 000 2h3a1 1 0 100-2h-3zm-3 4a1 1 0 100 2h.01a1 1 0 100-2H7zm3 0a1 1 0 100 2h3a1 1 0 100-2h-3z" clip-rule="evenodd"/></svg>',
|
|
499
|
+
NotebookEdit: '<svg viewBox="0 0 20 20" fill="currentColor"><path d="M9 4.804A7.968 7.968 0 005.5 4c-1.255 0-2.443.29-3.5.804v10A7.969 7.969 0 015.5 14c1.669 0 3.218.51 4.5 1.385A7.962 7.962 0 0114.5 14c1.255 0 2.443.29 3.5.804v-10A7.968 7.968 0 0014.5 4c-1.255 0-2.443.29-3.5.804V12a1 1 0 11-2 0V4.804z"/></svg>'
|
|
500
|
+
};
|
|
501
|
+
return icons[toolName] || '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M11.3 1.046A1 1 0 0112 2v5h4a1 1 0 01.82 1.573l-7 10.666a1 1 0 11-1.64-1.118L9.687 10H5a1 1 0 01-.82-1.573l7-10.666a1 1 0 011.12-.373z" clip-rule="evenodd"/></svg>';
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Render a file path with icon, directory breadcrumb, and filename
|
|
506
|
+
*/
|
|
507
|
+
renderFilePath(filePath) {
|
|
508
|
+
if (!filePath) return '';
|
|
509
|
+
const parts = filePath.split('/');
|
|
510
|
+
const fileName = parts.pop();
|
|
511
|
+
const dir = parts.join('/');
|
|
512
|
+
return `<div class="tool-param-file"><span class="file-icon">📄</span>${dir ? `<span class="file-dir">${this.escapeHtml(dir)}/</span>` : ''}<span class="file-name">${this.escapeHtml(fileName)}</span></div>`;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Render smart tool parameters based on tool type
|
|
517
|
+
*/
|
|
518
|
+
renderSmartParams(toolName, input) {
|
|
519
|
+
if (!input || Object.keys(input).length === 0) return '';
|
|
520
|
+
|
|
521
|
+
const normalizedName = toolName.replace(/^mcp__[^_]+__/, '');
|
|
522
|
+
|
|
523
|
+
switch (normalizedName) {
|
|
524
|
+
case 'Read':
|
|
525
|
+
return `<div class="tool-params">${this.renderFilePath(input.file_path)}${input.offset ? `<div style="margin-top:0.375rem;font-size:0.75rem;color:var(--color-text-secondary)">Lines ${input.offset}${input.limit ? '–' + (input.offset + input.limit) : '+'}</div>` : ''}</div>`;
|
|
526
|
+
|
|
527
|
+
case 'Write':
|
|
528
|
+
return `<div class="tool-params">${this.renderFilePath(input.file_path)}${input.content ? this.renderContentPreview(input.content, 'Content') : ''}</div>`;
|
|
529
|
+
|
|
530
|
+
case 'Edit': {
|
|
531
|
+
let html = `<div class="tool-params">${this.renderFilePath(input.file_path)}`;
|
|
532
|
+
if (input.old_string || input.new_string) {
|
|
533
|
+
html += `<div class="tool-param-diff" style="margin-top:0.5rem">`;
|
|
534
|
+
if (input.old_string) {
|
|
535
|
+
html += `<div class="diff-header">Remove</div><div class="diff-old">${this.escapeHtml(this.truncateContent(input.old_string, 500))}</div>`;
|
|
536
|
+
}
|
|
537
|
+
if (input.new_string) {
|
|
538
|
+
html += `<div class="diff-header">Add</div><div class="diff-new">${this.escapeHtml(this.truncateContent(input.new_string, 500))}</div>`;
|
|
539
|
+
}
|
|
540
|
+
html += '</div>';
|
|
541
|
+
}
|
|
542
|
+
return html + '</div>';
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
case 'Bash': {
|
|
546
|
+
const cmd = input.command || input.commands || '';
|
|
547
|
+
const cmdText = typeof cmd === 'string' ? cmd : JSON.stringify(cmd);
|
|
548
|
+
let html = `<div class="tool-params"><div class="tool-param-command"><span class="prompt-char">$</span><span class="command-text">${this.escapeHtml(cmdText)}</span></div>`;
|
|
549
|
+
if (input.description) html += `<div style="margin-top:0.375rem;font-size:0.75rem;color:var(--color-text-secondary)">${this.escapeHtml(input.description)}</div>`;
|
|
550
|
+
return html + '</div>';
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
case 'Glob':
|
|
554
|
+
return `<div class="tool-params"><div class="tool-param-query"><span class="query-icon">📁</span><code style="font-size:0.85rem">${this.escapeHtml(input.pattern || '')}</code></div>${input.path ? `<div style="margin-top:0.25rem;font-size:0.75rem;color:var(--color-text-secondary)">in ${this.escapeHtml(input.path)}</div>` : ''}</div>`;
|
|
555
|
+
|
|
556
|
+
case 'Grep':
|
|
557
|
+
return `<div class="tool-params"><div class="tool-param-query"><span class="query-icon">🔍</span><code style="font-size:0.85rem">${this.escapeHtml(input.pattern || '')}</code></div>${input.path ? `<div style="margin-top:0.25rem;font-size:0.75rem;color:var(--color-text-secondary)">in ${this.escapeHtml(input.path)}</div>` : ''}${input.glob ? `<div style="margin-top:0.125rem;font-size:0.7rem;color:var(--color-text-secondary)">files: ${this.escapeHtml(input.glob)}</div>` : ''}</div>`;
|
|
558
|
+
|
|
559
|
+
case 'WebFetch':
|
|
560
|
+
return `<div class="tool-params"><div class="tool-param-url"><span class="url-icon">🌐</span>${this.escapeHtml(input.url || '')}</div>${input.prompt ? `<div style="margin-top:0.375rem;font-size:0.8rem;color:var(--color-text-secondary)">${this.escapeHtml(this.truncateContent(input.prompt, 150))}</div>` : ''}</div>`;
|
|
561
|
+
|
|
562
|
+
case 'WebSearch':
|
|
563
|
+
return `<div class="tool-params"><div class="tool-param-query"><span class="query-icon">🔍</span><strong style="font-size:0.85rem">${this.escapeHtml(input.query || '')}</strong></div></div>`;
|
|
564
|
+
|
|
565
|
+
case 'TodoWrite':
|
|
566
|
+
if (input.todos && Array.isArray(input.todos)) {
|
|
567
|
+
const statusIcons = { completed: '✅', in_progress: '⚙', pending: '☐' };
|
|
568
|
+
const items = input.todos.map(t => `<div class="todo-item"><span class="todo-status">${statusIcons[t.status] || '☐'}</span><span class="todo-text">${this.escapeHtml(t.content || '')}</span></div>`).join('');
|
|
569
|
+
return `<div class="tool-params"><div class="tool-param-todos">${items}</div></div>`;
|
|
570
|
+
}
|
|
571
|
+
return this.renderJsonParams(input);
|
|
572
|
+
|
|
573
|
+
case 'Task':
|
|
574
|
+
return `<div class="tool-params">${input.description ? `<div style="font-weight:600;font-size:0.85rem;margin-bottom:0.375rem">${this.escapeHtml(input.description)}</div>` : ''}${input.prompt ? `<div style="font-size:0.8rem;color:var(--color-text-secondary);max-height:100px;overflow-y:auto;white-space:pre-wrap;word-break:break-word">${this.escapeHtml(this.truncateContent(input.prompt, 300))}</div>` : ''}${input.subagent_type ? `<div style="margin-top:0.375rem;font-size:0.7rem"><code style="background:var(--color-bg-secondary);padding:0.125rem 0.375rem;border-radius:0.25rem">${this.escapeHtml(input.subagent_type)}</code></div>` : ''}</div>`;
|
|
575
|
+
|
|
576
|
+
case 'NotebookEdit':
|
|
577
|
+
return `<div class="tool-params">${this.renderFilePath(input.notebook_path)}${input.new_source ? this.renderContentPreview(input.new_source, 'Cell content') : ''}</div>`;
|
|
578
|
+
|
|
579
|
+
default:
|
|
580
|
+
return this.renderJsonParams(input);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Render content preview with truncation
|
|
586
|
+
*/
|
|
587
|
+
renderContentPreview(content, label) {
|
|
588
|
+
const maxLen = 500;
|
|
589
|
+
const truncated = content.length > maxLen;
|
|
590
|
+
const displayContent = truncated ? content.substring(0, maxLen) : content;
|
|
591
|
+
const lineCount = content.split('\n').length;
|
|
592
|
+
return `<div class="tool-param-content-preview" style="margin-top:0.5rem"><div class="preview-header"><span>${this.escapeHtml(label)}</span><span style="font-weight:400">${lineCount} lines${truncated ? ' (truncated)' : ''}</span></div><div class="preview-body">${this.escapeHtml(displayContent)}</div>${truncated ? '<div class="preview-truncated">... ' + (content.length - maxLen) + ' more characters</div>' : ''}</div>`;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Render params as formatted JSON (default fallback for unknown tools)
|
|
597
|
+
*/
|
|
598
|
+
renderJsonParams(input) {
|
|
599
|
+
return `<div class="tool-params"><div class="tool-param-json"><pre>${this.escapeHtml(JSON.stringify(input, null, 2))}</pre></div></div>`;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Render tool use block with smart parameter display
|
|
496
604
|
*/
|
|
497
605
|
renderBlockToolUse(block, context) {
|
|
498
606
|
const div = document.createElement('div');
|
|
499
|
-
div.className = 'block-tool-use
|
|
607
|
+
div.className = 'block-tool-use';
|
|
500
608
|
|
|
501
609
|
const toolName = block.name || 'unknown';
|
|
502
610
|
const input = block.input || {};
|
|
503
611
|
|
|
504
612
|
div.innerHTML = `
|
|
505
|
-
<div class="
|
|
506
|
-
<
|
|
507
|
-
|
|
508
|
-
</svg>
|
|
509
|
-
<span class="font-semibold text-cyan-900 dark:text-cyan-200">Tool: <code class="font-mono bg-cyan-200 dark:bg-cyan-800 px-2 py-1 rounded text-sm">${this.escapeHtml(toolName)}</code></span>
|
|
613
|
+
<div class="tool-header">
|
|
614
|
+
<span class="tool-icon">${this.getToolIcon(toolName)}</span>
|
|
615
|
+
<span class="tool-name"><code>${this.escapeHtml(toolName)}</code></span>
|
|
510
616
|
</div>
|
|
511
|
-
${Object.keys(input).length > 0 ?
|
|
512
|
-
<div class="px-4 py-3">
|
|
513
|
-
<div class="text-xs uppercase tracking-wider text-cyan-700 dark:text-cyan-400 font-semibold mb-2">Parameters:</div>
|
|
514
|
-
<pre class="bg-white dark:bg-gray-900 p-3 rounded border border-cyan-200 dark:border-cyan-800 text-xs overflow-x-auto"><code class="language-json">${this.escapeHtml(JSON.stringify(input, null, 2))}</code></pre>
|
|
515
|
-
</div>
|
|
516
|
-
` : '<div class="px-4 py-2 text-sm text-cyan-700 dark:text-cyan-400">No parameters</div>'}
|
|
617
|
+
${Object.keys(input).length > 0 ? this.renderSmartParams(toolName, input) : ''}
|
|
517
618
|
`;
|
|
518
619
|
|
|
519
620
|
return div;
|
|
520
621
|
}
|
|
521
622
|
|
|
522
623
|
/**
|
|
523
|
-
* Render tool result block
|
|
624
|
+
* Render tool result block with smart content display
|
|
524
625
|
*/
|
|
525
626
|
renderBlockToolResult(block, context) {
|
|
526
627
|
const div = document.createElement('div');
|
|
527
628
|
const isError = block.is_error || false;
|
|
528
|
-
|
|
529
|
-
? 'block-tool-result mb-4 rounded-lg border border-red-200 dark:border-red-800 bg-red-50 dark:bg-red-950 overflow-hidden'
|
|
530
|
-
: 'block-tool-result mb-4 rounded-lg border border-green-200 dark:border-green-800 bg-green-50 dark:bg-green-950 overflow-hidden';
|
|
531
|
-
|
|
532
|
-
div.className = className;
|
|
629
|
+
div.className = `block-tool-result ${isError ? 'result-error' : 'result-success'}`;
|
|
533
630
|
|
|
534
631
|
const content = block.content || '';
|
|
632
|
+
const contentStr = typeof content === 'string' ? content : JSON.stringify(content, null, 2);
|
|
535
633
|
const toolUseId = block.tool_use_id || '';
|
|
536
|
-
const
|
|
634
|
+
const isLong = contentStr.length > 1500;
|
|
635
|
+
|
|
636
|
+
const iconSvg = isError
|
|
637
|
+
? '<svg viewBox="0 0 20 20" fill="currentColor"><path 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"/></svg>'
|
|
638
|
+
: '<svg viewBox="0 0 20 20" fill="currentColor"><path 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"/></svg>';
|
|
639
|
+
|
|
640
|
+
const displayContent = isLong ? contentStr.substring(0, 1500) : contentStr;
|
|
537
641
|
|
|
538
642
|
div.innerHTML = `
|
|
539
|
-
<div class="
|
|
540
|
-
<
|
|
541
|
-
|
|
542
|
-
<svg class="w-5 h-5 text-${statusColor}-600 dark:text-${statusColor}-400" fill="currentColor" viewBox="0 0 20 20">
|
|
543
|
-
<path 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"></path>
|
|
544
|
-
</svg>
|
|
545
|
-
<span class="font-semibold text-${statusColor}-900 dark:text-${statusColor}-200">Error</span>
|
|
546
|
-
` : `
|
|
547
|
-
<svg class="w-5 h-5 text-${statusColor}-600 dark:text-${statusColor}-400" fill="currentColor" viewBox="0 0 20 20">
|
|
548
|
-
<path 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"></path>
|
|
549
|
-
</svg>
|
|
550
|
-
<span class="font-semibold text-${statusColor}-900 dark:text-${statusColor}-200">Success</span>
|
|
551
|
-
`}
|
|
552
|
-
</div>
|
|
553
|
-
${toolUseId ? `<code class="text-xs text-${statusColor}-700 dark:text-${statusColor}-300">${this.escapeHtml(toolUseId)}</code>` : ''}
|
|
554
|
-
</div>
|
|
555
|
-
<div class="px-4 py-3 text-sm text-${statusColor}-900 dark:text-${statusColor}-200 whitespace-pre-wrap leading-relaxed overflow-x-auto">
|
|
556
|
-
${this.escapeHtml(typeof content === 'string' ? content : JSON.stringify(content, null, 2))}
|
|
643
|
+
<div class="result-header">
|
|
644
|
+
<span class="status-label">${iconSvg} ${isError ? 'Error' : 'Success'}</span>
|
|
645
|
+
${toolUseId ? `<span class="result-id">${this.escapeHtml(toolUseId)}</span>` : ''}
|
|
557
646
|
</div>
|
|
647
|
+
<div class="result-body${isLong ? ' collapsed' : ''}">${this.escapeHtml(displayContent)}</div>
|
|
648
|
+
${isLong ? '<button class="expand-btn" onclick="this.previousElementSibling.classList.toggle(\'collapsed\');this.textContent=this.textContent===\'Show more\'?\'Show less\':\'Show more\'">Show more</button>' : ''}
|
|
558
649
|
`;
|
|
559
650
|
|
|
560
651
|
return div;
|
|
@@ -565,14 +656,19 @@ class StreamingRenderer {
|
|
|
565
656
|
*/
|
|
566
657
|
renderBlockImage(block, context) {
|
|
567
658
|
const div = document.createElement('div');
|
|
568
|
-
div.className = 'block-image
|
|
659
|
+
div.className = 'block-image';
|
|
569
660
|
|
|
570
|
-
|
|
661
|
+
let src = block.image || block.src || '';
|
|
571
662
|
const alt = block.alt || 'Image';
|
|
572
663
|
|
|
664
|
+
// Handle base64 data
|
|
665
|
+
if (block.data && block.media_type) {
|
|
666
|
+
src = `data:${block.media_type};base64,${block.data}`;
|
|
667
|
+
}
|
|
668
|
+
|
|
573
669
|
div.innerHTML = `
|
|
574
|
-
<img src="${this.escapeHtml(src)}" alt="${this.escapeHtml(alt)}"
|
|
575
|
-
${block.alt ? `<div class="
|
|
670
|
+
<img src="${this.escapeHtml(src)}" alt="${this.escapeHtml(alt)}" loading="lazy">
|
|
671
|
+
${block.alt ? `<div class="image-caption">${this.escapeHtml(alt)}</div>` : ''}
|
|
576
672
|
`;
|
|
577
673
|
|
|
578
674
|
return div;
|
|
@@ -583,19 +679,14 @@ class StreamingRenderer {
|
|
|
583
679
|
*/
|
|
584
680
|
renderBlockBash(block, context) {
|
|
585
681
|
const div = document.createElement('div');
|
|
586
|
-
div.className = 'block-bash
|
|
682
|
+
div.className = 'block-bash';
|
|
587
683
|
|
|
588
684
|
const command = block.command || block.code || '';
|
|
589
685
|
const output = block.output || '';
|
|
590
686
|
|
|
591
687
|
div.innerHTML = `
|
|
592
|
-
<div class="
|
|
593
|
-
|
|
594
|
-
<code class="font-mono text-gray-200 text-sm overflow-x-auto w-full">${this.escapeHtml(command)}</code>
|
|
595
|
-
</div>
|
|
596
|
-
${output ? `
|
|
597
|
-
<pre class="px-4 py-3 text-gray-300 text-sm overflow-x-auto"><code>${this.escapeHtml(output)}</code></pre>
|
|
598
|
-
` : ''}
|
|
688
|
+
<div class="bash-command"><span class="prompt">$</span><code>${this.escapeHtml(command)}</code></div>
|
|
689
|
+
${output ? `<pre class="bash-output"><code>${this.escapeHtml(output)}</code></pre>` : ''}
|
|
599
690
|
`;
|
|
600
691
|
|
|
601
692
|
return div;
|
|
@@ -606,40 +697,77 @@ class StreamingRenderer {
|
|
|
606
697
|
*/
|
|
607
698
|
renderBlockSystem(block, context) {
|
|
608
699
|
const div = document.createElement('div');
|
|
609
|
-
div.className = 'block-system
|
|
700
|
+
div.className = 'block-system';
|
|
610
701
|
|
|
611
702
|
div.innerHTML = `
|
|
612
|
-
<div class="
|
|
613
|
-
|
|
703
|
+
<div class="system-header">Session Information</div>
|
|
704
|
+
<div class="system-body">
|
|
705
|
+
${block.model ? `<div class="sys-field"><span class="sys-label">Model</span><span class="sys-value"><code>${this.escapeHtml(block.model)}</code></span></div>` : ''}
|
|
706
|
+
${block.cwd ? `<div class="sys-field"><span class="sys-label">Directory</span><span class="sys-value"><code>${this.escapeHtml(block.cwd)}</code></span></div>` : ''}
|
|
707
|
+
${block.session_id ? `<div class="sys-field"><span class="sys-label">Session</span><span class="sys-value"><code>${this.escapeHtml(block.session_id)}</code></span></div>` : ''}
|
|
708
|
+
${block.tools && Array.isArray(block.tools) ? `<div class="sys-field" style="flex-direction:column;gap:0.375rem"><span class="sys-label">Tools (${block.tools.length})</span><div class="tools-list">${block.tools.map(t => `<span class="tool-badge">${this.escapeHtml(t)}</span>`).join('')}</div></div>` : ''}
|
|
614
709
|
</div>
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
710
|
+
`;
|
|
711
|
+
|
|
712
|
+
return div;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Render result block (execution summary)
|
|
717
|
+
*/
|
|
718
|
+
renderBlockResult(block, context) {
|
|
719
|
+
const div = document.createElement('div');
|
|
720
|
+
const isError = block.is_error || false;
|
|
721
|
+
div.className = `block-result ${isError ? 'result-err' : 'result-ok'}`;
|
|
722
|
+
|
|
723
|
+
const duration = block.duration_ms ? (block.duration_ms / 1000).toFixed(1) + 's' : '';
|
|
724
|
+
const cost = block.total_cost_usd ? '$' + block.total_cost_usd.toFixed(4) : '';
|
|
725
|
+
const turns = block.num_turns || '';
|
|
726
|
+
|
|
727
|
+
div.innerHTML = `
|
|
728
|
+
<div class="result-summary-header">
|
|
729
|
+
${isError
|
|
730
|
+
? '<svg viewBox="0 0 20 20" fill="currentColor"><path 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"/></svg>'
|
|
731
|
+
: '<svg viewBox="0 0 20 20" fill="currentColor"><path 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"/></svg>'}
|
|
732
|
+
<span class="result-title">${isError ? 'Execution Failed' : 'Execution Complete'}</span>
|
|
627
733
|
</div>
|
|
734
|
+
<div class="result-stats">
|
|
735
|
+
${duration ? `<div class="result-stat"><span class="stat-icon">⏲</span><span class="stat-value">${this.escapeHtml(duration)}</span><span class="stat-label">duration</span></div>` : ''}
|
|
736
|
+
${cost ? `<div class="result-stat"><span class="stat-icon">💰</span><span class="stat-value">${this.escapeHtml(cost)}</span><span class="stat-label">cost</span></div>` : ''}
|
|
737
|
+
${turns ? `<div class="result-stat"><span class="stat-icon">🔄</span><span class="stat-value">${this.escapeHtml(String(turns))}</span><span class="stat-label">turns</span></div>` : ''}
|
|
738
|
+
</div>
|
|
739
|
+
${block.result ? `<div class="result-content">${this.escapeHtml(typeof block.result === 'string' ? block.result : JSON.stringify(block.result, null, 2))}</div>` : ''}
|
|
628
740
|
`;
|
|
629
741
|
|
|
630
742
|
return div;
|
|
631
743
|
}
|
|
632
744
|
|
|
633
745
|
/**
|
|
634
|
-
* Render generic block
|
|
746
|
+
* Render generic block with formatted key-value pairs
|
|
635
747
|
*/
|
|
636
748
|
renderBlockGeneric(block, context) {
|
|
637
749
|
const div = document.createElement('div');
|
|
638
|
-
div.className = 'block-generic
|
|
750
|
+
div.className = 'block-generic';
|
|
751
|
+
|
|
752
|
+
// Show key-value pairs instead of raw JSON
|
|
753
|
+
const fieldsHtml = Object.entries(block)
|
|
754
|
+
.filter(([key]) => key !== 'type')
|
|
755
|
+
.map(([key, value]) => {
|
|
756
|
+
let displayValue;
|
|
757
|
+
if (typeof value === 'string') {
|
|
758
|
+
displayValue = value.length > 200 ? value.substring(0, 200) + '...' : value;
|
|
759
|
+
} else if (typeof value === 'number' || typeof value === 'boolean') {
|
|
760
|
+
displayValue = String(value);
|
|
761
|
+
} else {
|
|
762
|
+
displayValue = JSON.stringify(value, null, 2);
|
|
763
|
+
if (displayValue.length > 200) displayValue = displayValue.substring(0, 200) + '...';
|
|
764
|
+
}
|
|
765
|
+
return `<div class="generic-field"><span class="field-key">${this.escapeHtml(key)}:</span><span class="field-value">${this.escapeHtml(displayValue)}</span></div>`;
|
|
766
|
+
}).join('');
|
|
639
767
|
|
|
640
768
|
div.innerHTML = `
|
|
641
|
-
<div class="
|
|
642
|
-
<
|
|
769
|
+
<div class="generic-type">${this.escapeHtml(block.type)}</div>
|
|
770
|
+
<div class="generic-fields">${fieldsHtml}</div>
|
|
643
771
|
`;
|
|
644
772
|
|
|
645
773
|
return div;
|
|
@@ -650,16 +778,16 @@ class StreamingRenderer {
|
|
|
650
778
|
*/
|
|
651
779
|
renderBlockError(block, error) {
|
|
652
780
|
const div = document.createElement('div');
|
|
653
|
-
div.className = 'block-error
|
|
781
|
+
div.className = 'block-error';
|
|
654
782
|
|
|
655
783
|
div.innerHTML = `
|
|
656
|
-
<div
|
|
657
|
-
<svg
|
|
658
|
-
<path 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"
|
|
784
|
+
<div style="display:flex;align-items:flex-start;gap:0.625rem">
|
|
785
|
+
<svg viewBox="0 0 20 20" fill="currentColor" style="color:#ef4444;flex-shrink:0;margin-top:0.125rem">
|
|
786
|
+
<path 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"/>
|
|
659
787
|
</svg>
|
|
660
|
-
<div
|
|
661
|
-
<
|
|
662
|
-
<
|
|
788
|
+
<div>
|
|
789
|
+
<div style="font-weight:600;color:#991b1b">Render Error</div>
|
|
790
|
+
<div style="font-size:0.85rem;color:#7f1d1d;margin-top:0.25rem">${this.escapeHtml(error.message)}</div>
|
|
663
791
|
</div>
|
|
664
792
|
</div>
|
|
665
793
|
`;
|
|
@@ -1053,33 +1181,21 @@ class StreamingRenderer {
|
|
|
1053
1181
|
* Render tool use event - for backward compatibility
|
|
1054
1182
|
*/
|
|
1055
1183
|
renderToolUse(event) {
|
|
1056
|
-
|
|
1057
|
-
|
|
1184
|
+
// Use the new block-based renderer for consistency
|
|
1185
|
+
const block = {
|
|
1186
|
+
type: 'tool_use',
|
|
1187
|
+
name: event.toolName || event.tool || 'unknown',
|
|
1188
|
+
input: event.input || {}
|
|
1189
|
+
};
|
|
1190
|
+
const div = this.renderBlockToolUse(block, event);
|
|
1191
|
+
div.className = 'event-tool-use mb-3';
|
|
1058
1192
|
div.dataset.eventId = event.id || '';
|
|
1059
1193
|
div.dataset.eventType = 'tool_use';
|
|
1060
|
-
|
|
1061
|
-
const toolName = event.toolName || event.tool || 'unknown';
|
|
1062
|
-
const input = event.input || {};
|
|
1063
|
-
|
|
1064
|
-
div.innerHTML = `
|
|
1065
|
-
<div class="px-4 py-3 border-b border-cyan-200 dark:border-cyan-800 flex items-center gap-2 bg-cyan-100 dark:bg-cyan-900">
|
|
1066
|
-
<svg class="w-5 h-5 text-cyan-600 dark:text-cyan-400" fill="currentColor" viewBox="0 0 20 20">
|
|
1067
|
-
<path fill-rule="evenodd" d="M11.3 1.046A1 1 0 0112 2v5h4a1 1 0 01.82 1.573l-7 10.666a1 1 0 11-1.64-1.118L9.687 10H5a1 1 0 01-.82-1.573l7-10.666a1 1 0 011.12-.373zM14.6 15.477l-5.223-7.912h-3.5l5.223 7.912h3.5z" clip-rule="evenodd"></path>
|
|
1068
|
-
</svg>
|
|
1069
|
-
<span class="font-semibold text-cyan-900 dark:text-cyan-200">Tool Call: <code class="font-mono bg-cyan-200 dark:bg-cyan-800 px-2 py-1 rounded text-sm">${this.escapeHtml(toolName)}</code></span>
|
|
1070
|
-
</div>
|
|
1071
|
-
${Object.keys(input).length > 0 ? `
|
|
1072
|
-
<div class="px-4 py-3">
|
|
1073
|
-
<div class="text-xs uppercase tracking-wider text-cyan-700 dark:text-cyan-400 font-semibold mb-2">Input Parameters:</div>
|
|
1074
|
-
<pre class="bg-white dark:bg-gray-900 p-3 rounded border border-cyan-200 dark:border-cyan-800 text-xs overflow-x-auto"><code class="language-json">${this.escapeHtml(JSON.stringify(input, null, 2))}</code></pre>
|
|
1075
|
-
</div>
|
|
1076
|
-
` : '<div class="px-4 py-2 text-sm text-cyan-700 dark:text-cyan-400">No input parameters</div>'}
|
|
1077
|
-
`;
|
|
1078
1194
|
return div;
|
|
1079
1195
|
}
|
|
1080
1196
|
|
|
1081
1197
|
/**
|
|
1082
|
-
* Render generic event
|
|
1198
|
+
* Render generic event with formatted key-value pairs
|
|
1083
1199
|
*/
|
|
1084
1200
|
renderGeneric(event) {
|
|
1085
1201
|
const div = document.createElement('div');
|
|
@@ -1088,12 +1204,31 @@ class StreamingRenderer {
|
|
|
1088
1204
|
div.dataset.eventType = event.type;
|
|
1089
1205
|
|
|
1090
1206
|
const time = new Date(event.timestamp).toLocaleTimeString();
|
|
1207
|
+
|
|
1208
|
+
// Format event data as key-value pairs
|
|
1209
|
+
const fieldsHtml = Object.entries(event)
|
|
1210
|
+
.filter(([key]) => !['type', 'timestamp'].includes(key))
|
|
1211
|
+
.map(([key, value]) => {
|
|
1212
|
+
let displayValue;
|
|
1213
|
+
if (typeof value === 'string') {
|
|
1214
|
+
displayValue = value.length > 100 ? value.substring(0, 100) + '...' : value;
|
|
1215
|
+
} else if (typeof value === 'number' || typeof value === 'boolean') {
|
|
1216
|
+
displayValue = String(value);
|
|
1217
|
+
} else if (value === null) {
|
|
1218
|
+
displayValue = 'null';
|
|
1219
|
+
} else {
|
|
1220
|
+
displayValue = JSON.stringify(value);
|
|
1221
|
+
if (displayValue.length > 100) displayValue = displayValue.substring(0, 100) + '...';
|
|
1222
|
+
}
|
|
1223
|
+
return `<div style="font-size:0.75rem;margin-bottom:0.25rem"><span style="font-weight:600;color:var(--color-text-secondary)">${this.escapeHtml(key)}:</span> <span style="font-family:'Monaco','Menlo','Ubuntu Mono',monospace">${this.escapeHtml(displayValue)}</span></div>`;
|
|
1224
|
+
}).join('');
|
|
1225
|
+
|
|
1091
1226
|
div.innerHTML = `
|
|
1092
|
-
<div
|
|
1093
|
-
<span
|
|
1094
|
-
<span
|
|
1227
|
+
<div style="display:flex;justify-content:space-between;margin-bottom:0.5rem">
|
|
1228
|
+
<span style="font-weight:600;color:var(--color-text-primary)">${this.escapeHtml(event.type)}</span>
|
|
1229
|
+
<span style="font-size:0.75rem;color:var(--color-text-secondary)">${time}</span>
|
|
1095
1230
|
</div>
|
|
1096
|
-
<
|
|
1231
|
+
<div>${fieldsHtml || '<span style="color:var(--color-text-secondary);font-size:0.75rem">No additional data</span>'}</div>
|
|
1097
1232
|
`;
|
|
1098
1233
|
return div;
|
|
1099
1234
|
}
|