@xcanwin/manyoyo 5.6.9 → 5.6.10
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/web/frontend/app.css +148 -0
- package/lib/web/frontend/app.js +213 -6
- package/lib/web/server.js +145 -27
- package/package.json +1 -1
package/lib/web/frontend/app.css
CHANGED
|
@@ -1047,6 +1047,154 @@ body.command-mode .msg.origin-agent .bubble {
|
|
|
1047
1047
|
line-height: 1.55;
|
|
1048
1048
|
}
|
|
1049
1049
|
|
|
1050
|
+
.trace-bubble {
|
|
1051
|
+
padding: 12px;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
.trace-structured {
|
|
1055
|
+
display: flex;
|
|
1056
|
+
flex-direction: column;
|
|
1057
|
+
gap: 10px;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
.trace-summary {
|
|
1061
|
+
display: flex;
|
|
1062
|
+
flex-direction: column;
|
|
1063
|
+
gap: 6px;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
.trace-summary-line {
|
|
1067
|
+
padding: 7px 10px;
|
|
1068
|
+
border-radius: 8px;
|
|
1069
|
+
border: 1px dashed rgba(181, 146, 99, 0.45);
|
|
1070
|
+
background: rgba(255, 250, 242, 0.82);
|
|
1071
|
+
color: var(--muted);
|
|
1072
|
+
font-size: 12px;
|
|
1073
|
+
line-height: 1.45;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
.trace-flow {
|
|
1077
|
+
display: flex;
|
|
1078
|
+
flex-direction: column;
|
|
1079
|
+
gap: 8px;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
.trace-card {
|
|
1083
|
+
border: 1px solid rgba(181, 146, 99, 0.32);
|
|
1084
|
+
border-left-width: 3px;
|
|
1085
|
+
border-radius: 10px;
|
|
1086
|
+
background: rgba(255, 255, 255, 0.88);
|
|
1087
|
+
overflow: hidden;
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
.trace-card.trace-tone-command {
|
|
1091
|
+
border-left-color: var(--subaccent);
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
.trace-card.trace-tone-mcp {
|
|
1095
|
+
border-left-color: var(--accent);
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
.trace-card.trace-tone-note {
|
|
1099
|
+
border-left-color: #6f62b5;
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
.trace-card.trace-tone-status {
|
|
1103
|
+
border-left-color: #7d8aa1;
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
.trace-card.trace-tone-error {
|
|
1107
|
+
border-left-color: var(--danger);
|
|
1108
|
+
background: rgba(255, 239, 236, 0.92);
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
.trace-card.trace-tone-neutral {
|
|
1112
|
+
border-left-color: var(--line-strong);
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
.trace-card-summary {
|
|
1116
|
+
list-style: none;
|
|
1117
|
+
display: flex;
|
|
1118
|
+
align-items: center;
|
|
1119
|
+
gap: 8px;
|
|
1120
|
+
padding: 9px 10px;
|
|
1121
|
+
cursor: default;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
details.trace-card > .trace-card-summary {
|
|
1125
|
+
cursor: pointer;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
.trace-card-summary::-webkit-details-marker {
|
|
1129
|
+
display: none;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
.trace-card-badge {
|
|
1133
|
+
flex: 0 0 auto;
|
|
1134
|
+
display: inline-flex;
|
|
1135
|
+
align-items: center;
|
|
1136
|
+
justify-content: center;
|
|
1137
|
+
min-width: 42px;
|
|
1138
|
+
padding: 2px 7px;
|
|
1139
|
+
border-radius: 999px;
|
|
1140
|
+
background: rgba(31, 26, 20, 0.08);
|
|
1141
|
+
color: var(--text);
|
|
1142
|
+
font-size: 11px;
|
|
1143
|
+
font-weight: 700;
|
|
1144
|
+
letter-spacing: 0.2px;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
.trace-card-title {
|
|
1148
|
+
min-width: 0;
|
|
1149
|
+
flex: 1;
|
|
1150
|
+
color: var(--text);
|
|
1151
|
+
font-size: 12px;
|
|
1152
|
+
font-weight: 600;
|
|
1153
|
+
line-height: 1.45;
|
|
1154
|
+
word-break: break-word;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
.trace-card-phase {
|
|
1158
|
+
flex: 0 0 auto;
|
|
1159
|
+
color: var(--muted);
|
|
1160
|
+
font-size: 11px;
|
|
1161
|
+
font-weight: 700;
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
.trace-card-body {
|
|
1165
|
+
padding: 0 10px 10px;
|
|
1166
|
+
display: flex;
|
|
1167
|
+
flex-direction: column;
|
|
1168
|
+
gap: 8px;
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
.trace-card-body-section {
|
|
1172
|
+
display: flex;
|
|
1173
|
+
flex-direction: column;
|
|
1174
|
+
gap: 4px;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
.trace-card-body-label {
|
|
1178
|
+
color: var(--muted);
|
|
1179
|
+
font-size: 11px;
|
|
1180
|
+
font-weight: 700;
|
|
1181
|
+
letter-spacing: 0.2px;
|
|
1182
|
+
text-transform: uppercase;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
.trace-card-body-pre {
|
|
1186
|
+
margin: 0;
|
|
1187
|
+
padding: 8px 9px;
|
|
1188
|
+
border-radius: 8px;
|
|
1189
|
+
background: rgba(31, 26, 20, 0.05);
|
|
1190
|
+
color: var(--text);
|
|
1191
|
+
white-space: pre-wrap;
|
|
1192
|
+
word-break: break-word;
|
|
1193
|
+
font-family: var(--font-mono);
|
|
1194
|
+
font-size: 12px;
|
|
1195
|
+
line-height: 1.5;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1050
1198
|
.composer {
|
|
1051
1199
|
border-top: 1px solid rgba(181, 146, 99, 0.45);
|
|
1052
1200
|
margin-top: 12px;
|
package/lib/web/frontend/app.js
CHANGED
|
@@ -190,6 +190,198 @@
|
|
|
190
190
|
bubble.appendChild(pre);
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
function stringifyPrettyJson(value) {
|
|
194
|
+
if (value === undefined || value === null) {
|
|
195
|
+
return '';
|
|
196
|
+
}
|
|
197
|
+
if (typeof value === 'string') {
|
|
198
|
+
return value;
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
return JSON.stringify(value, null, 2);
|
|
202
|
+
} catch (e) {
|
|
203
|
+
return String(value);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function humanizeTraceKind(traceEvent) {
|
|
208
|
+
const kind = traceEvent && traceEvent.kind ? String(traceEvent.kind) : '';
|
|
209
|
+
if (kind === 'thread') return '会话';
|
|
210
|
+
if (kind === 'turn') return '回合';
|
|
211
|
+
if (kind === 'status') return '状态';
|
|
212
|
+
if (kind === 'agent_message') return '说明';
|
|
213
|
+
if (kind === 'command') return '命令';
|
|
214
|
+
if (kind === 'mcp') return 'MCP';
|
|
215
|
+
if (kind === 'tool') return '工具';
|
|
216
|
+
if (kind === 'error') return '错误';
|
|
217
|
+
return '事件';
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function humanizeTracePhase(traceEvent) {
|
|
221
|
+
const phase = traceEvent && traceEvent.phase ? String(traceEvent.phase) : '';
|
|
222
|
+
if (phase === 'started') return '开始';
|
|
223
|
+
if (phase === 'completed') return '完成';
|
|
224
|
+
const status = traceEvent && traceEvent.status ? String(traceEvent.status).trim() : '';
|
|
225
|
+
return status;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function buildStructuredTraceResidualLines(message) {
|
|
229
|
+
const lines = String(message && message.content ? message.content : '')
|
|
230
|
+
.split('\n')
|
|
231
|
+
.map(function (line) {
|
|
232
|
+
return String(line || '').trim();
|
|
233
|
+
})
|
|
234
|
+
.filter(Boolean);
|
|
235
|
+
const traceEvents = Array.isArray(message && message.traceEvents) ? message.traceEvents : [];
|
|
236
|
+
const consumed = new Map();
|
|
237
|
+
traceEvents.forEach(function (traceEvent) {
|
|
238
|
+
const key = traceEvent && traceEvent.text ? String(traceEvent.text).trim() : '';
|
|
239
|
+
if (!key) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
consumed.set(key, (consumed.get(key) || 0) + 1);
|
|
243
|
+
});
|
|
244
|
+
return lines.filter(function (line) {
|
|
245
|
+
if (!line || line === '[执行过程]') {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
const remaining = consumed.get(line) || 0;
|
|
249
|
+
if (remaining > 0) {
|
|
250
|
+
consumed.set(line, remaining - 1);
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
return true;
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function resolveTraceTone(traceEvent) {
|
|
258
|
+
const kind = traceEvent && traceEvent.kind ? String(traceEvent.kind) : '';
|
|
259
|
+
if (kind === 'command') return 'command';
|
|
260
|
+
if (kind === 'mcp') return 'mcp';
|
|
261
|
+
if (kind === 'error') return 'error';
|
|
262
|
+
if (kind === 'agent_message') return 'note';
|
|
263
|
+
if (kind === 'status') return 'status';
|
|
264
|
+
return 'neutral';
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function appendTraceCardBody(cardBody, label, value) {
|
|
268
|
+
const text = stringifyPrettyJson(value).trim();
|
|
269
|
+
if (!text) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
const section = document.createElement('div');
|
|
273
|
+
section.className = 'trace-card-body-section';
|
|
274
|
+
|
|
275
|
+
const title = document.createElement('div');
|
|
276
|
+
title.className = 'trace-card-body-label';
|
|
277
|
+
title.textContent = label;
|
|
278
|
+
section.appendChild(title);
|
|
279
|
+
|
|
280
|
+
const pre = document.createElement('pre');
|
|
281
|
+
pre.className = 'trace-card-body-pre';
|
|
282
|
+
pre.textContent = text;
|
|
283
|
+
section.appendChild(pre);
|
|
284
|
+
|
|
285
|
+
cardBody.appendChild(section);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function createTraceEventCard(traceEvent) {
|
|
289
|
+
const event = traceEvent && typeof traceEvent === 'object' ? traceEvent : {};
|
|
290
|
+
const bodyParts = [];
|
|
291
|
+
if (event.kind === 'command' && event.command) {
|
|
292
|
+
bodyParts.push({ label: '命令', value: event.command });
|
|
293
|
+
}
|
|
294
|
+
if (event.kind === 'mcp') {
|
|
295
|
+
if (event.argumentSummary) {
|
|
296
|
+
bodyParts.push({ label: '参数摘要', value: event.argumentSummary });
|
|
297
|
+
}
|
|
298
|
+
if (event.arguments) {
|
|
299
|
+
bodyParts.push({ label: '参数', value: event.arguments });
|
|
300
|
+
}
|
|
301
|
+
if (event.result) {
|
|
302
|
+
bodyParts.push({ label: '结果', value: event.result });
|
|
303
|
+
}
|
|
304
|
+
if (event.error) {
|
|
305
|
+
bodyParts.push({ label: '错误', value: event.error });
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (event.kind === 'tool' && event.toolName) {
|
|
309
|
+
bodyParts.push({ label: '工具', value: event.toolName });
|
|
310
|
+
}
|
|
311
|
+
if ((event.kind === 'agent_message' || event.kind === 'status' || event.kind === 'error') && event.detail) {
|
|
312
|
+
bodyParts.push({ label: '详情', value: event.detail });
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const hasBody = bodyParts.length > 0;
|
|
316
|
+
const card = document.createElement(hasBody ? 'details' : 'div');
|
|
317
|
+
card.className = 'trace-card trace-tone-' + resolveTraceTone(event);
|
|
318
|
+
if (hasBody && event.kind === 'error') {
|
|
319
|
+
card.open = true;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const header = document.createElement(hasBody ? 'summary' : 'div');
|
|
323
|
+
header.className = 'trace-card-summary';
|
|
324
|
+
|
|
325
|
+
const badge = document.createElement('span');
|
|
326
|
+
badge.className = 'trace-card-badge';
|
|
327
|
+
badge.textContent = humanizeTraceKind(event);
|
|
328
|
+
header.appendChild(badge);
|
|
329
|
+
|
|
330
|
+
const title = document.createElement('span');
|
|
331
|
+
title.className = 'trace-card-title';
|
|
332
|
+
title.textContent = event && event.text ? String(event.text) : '事件';
|
|
333
|
+
header.appendChild(title);
|
|
334
|
+
|
|
335
|
+
const phaseText = humanizeTracePhase(event);
|
|
336
|
+
if (phaseText) {
|
|
337
|
+
const phase = document.createElement('span');
|
|
338
|
+
phase.className = 'trace-card-phase';
|
|
339
|
+
phase.textContent = phaseText;
|
|
340
|
+
header.appendChild(phase);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
card.appendChild(header);
|
|
344
|
+
|
|
345
|
+
if (hasBody) {
|
|
346
|
+
const body = document.createElement('div');
|
|
347
|
+
body.className = 'trace-card-body';
|
|
348
|
+
bodyParts.forEach(function (part) {
|
|
349
|
+
appendTraceCardBody(body, part.label, part.value);
|
|
350
|
+
});
|
|
351
|
+
card.appendChild(body);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return card;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function appendStructuredTraceContent(bubble, message) {
|
|
358
|
+
bubble.classList.add('trace-bubble');
|
|
359
|
+
const container = document.createElement('div');
|
|
360
|
+
container.className = 'trace-structured';
|
|
361
|
+
|
|
362
|
+
const residualLines = buildStructuredTraceResidualLines(message);
|
|
363
|
+
if (residualLines.length) {
|
|
364
|
+
const summary = document.createElement('div');
|
|
365
|
+
summary.className = 'trace-summary';
|
|
366
|
+
residualLines.forEach(function (line) {
|
|
367
|
+
const item = document.createElement('div');
|
|
368
|
+
item.className = 'trace-summary-line';
|
|
369
|
+
item.textContent = line;
|
|
370
|
+
summary.appendChild(item);
|
|
371
|
+
});
|
|
372
|
+
container.appendChild(summary);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const flow = document.createElement('div');
|
|
376
|
+
flow.className = 'trace-flow';
|
|
377
|
+
(Array.isArray(message && message.traceEvents) ? message.traceEvents : []).forEach(function (traceEvent) {
|
|
378
|
+
flow.appendChild(createTraceEventCard(traceEvent));
|
|
379
|
+
});
|
|
380
|
+
container.appendChild(flow);
|
|
381
|
+
|
|
382
|
+
bubble.appendChild(container);
|
|
383
|
+
}
|
|
384
|
+
|
|
193
385
|
function roleName(role, message) {
|
|
194
386
|
if (role === 'user') return '我';
|
|
195
387
|
if (role === 'assistant') {
|
|
@@ -1763,8 +1955,16 @@
|
|
|
1763
1955
|
const bubble = document.createElement('div');
|
|
1764
1956
|
bubble.className = 'bubble';
|
|
1765
1957
|
|
|
1958
|
+
const shouldRenderStructuredTrace = Boolean(
|
|
1959
|
+
msg
|
|
1960
|
+
&& msg.streamTrace
|
|
1961
|
+
&& Array.isArray(msg.traceEvents)
|
|
1962
|
+
&& msg.traceEvents.length
|
|
1963
|
+
);
|
|
1766
1964
|
const shouldRenderMarkdown = Boolean(!msg.streamTrace && markdownRenderer && markdownRenderer.shouldRenderMessage(msg));
|
|
1767
|
-
if (
|
|
1965
|
+
if (shouldRenderStructuredTrace) {
|
|
1966
|
+
appendStructuredTraceContent(bubble, msg);
|
|
1967
|
+
} else if (shouldRenderMarkdown) {
|
|
1768
1968
|
const markdownNode = document.createElement('div');
|
|
1769
1969
|
markdownNode.className = 'md-content';
|
|
1770
1970
|
let renderedMarkdown = '';
|
|
@@ -2070,7 +2270,8 @@
|
|
|
2070
2270
|
content: '[执行过程]\n等待 Agent 启动…',
|
|
2071
2271
|
timestamp: new Date().toISOString(),
|
|
2072
2272
|
mode: 'agent',
|
|
2073
|
-
streamTrace: true
|
|
2273
|
+
streamTrace: true,
|
|
2274
|
+
traceEvents: []
|
|
2074
2275
|
};
|
|
2075
2276
|
if (state.active === sessionName) {
|
|
2076
2277
|
state.messages.push(traceMessage);
|
|
@@ -2078,7 +2279,7 @@
|
|
|
2078
2279
|
return traceMessage.id;
|
|
2079
2280
|
}
|
|
2080
2281
|
|
|
2081
|
-
function updateAgentTraceMessageLocal(sessionName, traceMessageId, content) {
|
|
2282
|
+
function updateAgentTraceMessageLocal(sessionName, traceMessageId, content, traceEvent) {
|
|
2082
2283
|
if (state.active !== sessionName) {
|
|
2083
2284
|
return;
|
|
2084
2285
|
}
|
|
@@ -2089,6 +2290,12 @@
|
|
|
2089
2290
|
}
|
|
2090
2291
|
message.content = String(content || '');
|
|
2091
2292
|
message.timestamp = new Date().toISOString();
|
|
2293
|
+
if (traceEvent && typeof traceEvent === 'object') {
|
|
2294
|
+
if (!Array.isArray(message.traceEvents)) {
|
|
2295
|
+
message.traceEvents = [];
|
|
2296
|
+
}
|
|
2297
|
+
message.traceEvents.push(traceEvent);
|
|
2298
|
+
}
|
|
2092
2299
|
return;
|
|
2093
2300
|
}
|
|
2094
2301
|
}
|
|
@@ -2133,7 +2340,7 @@
|
|
|
2133
2340
|
renderMessages(state.messages, { stickToBottom: true });
|
|
2134
2341
|
syncUi();
|
|
2135
2342
|
|
|
2136
|
-
function pushTraceLine(text) {
|
|
2343
|
+
function pushTraceLine(text, traceEvent) {
|
|
2137
2344
|
const line = String(text || '').trim();
|
|
2138
2345
|
if (!line) {
|
|
2139
2346
|
return;
|
|
@@ -2142,7 +2349,7 @@
|
|
|
2142
2349
|
return;
|
|
2143
2350
|
}
|
|
2144
2351
|
traceLines.push(line);
|
|
2145
|
-
updateAgentTraceMessageLocal(sessionName, traceMessageId, traceLines.join('\n'));
|
|
2352
|
+
updateAgentTraceMessageLocal(sessionName, traceMessageId, traceLines.join('\n'), traceEvent);
|
|
2146
2353
|
if (state.active === sessionName) {
|
|
2147
2354
|
renderMessages(state.messages, { stickToBottom: true });
|
|
2148
2355
|
}
|
|
@@ -2170,7 +2377,7 @@
|
|
|
2170
2377
|
return;
|
|
2171
2378
|
}
|
|
2172
2379
|
if (event.type === 'trace') {
|
|
2173
|
-
pushTraceLine(event.text || '');
|
|
2380
|
+
pushTraceLine(event.text || '', event.traceEvent || null);
|
|
2174
2381
|
return;
|
|
2175
2382
|
}
|
|
2176
2383
|
if (event.type === 'result') {
|
package/lib/web/server.js
CHANGED
|
@@ -376,9 +376,9 @@ function buildAgentPromptWithHistory(history, prompt) {
|
|
|
376
376
|
].join('\n');
|
|
377
377
|
}
|
|
378
378
|
|
|
379
|
-
function
|
|
379
|
+
function prepareCodexTraceEvent(payload) {
|
|
380
380
|
if (!payload || typeof payload !== 'object') {
|
|
381
|
-
return
|
|
381
|
+
return null;
|
|
382
382
|
}
|
|
383
383
|
|
|
384
384
|
const eventType = typeof payload.type === 'string' ? payload.type : '';
|
|
@@ -431,66 +431,173 @@ function prepareCodexTraceDisplayLine(payload) {
|
|
|
431
431
|
return parts.slice(0, 3).join(', ');
|
|
432
432
|
}
|
|
433
433
|
|
|
434
|
+
function pickDisplayStatus(defaultStatus) {
|
|
435
|
+
const status = String(itemStatus || defaultStatus || '').trim();
|
|
436
|
+
return status || '';
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function createTraceEvent(kind, textValue, extra = {}) {
|
|
440
|
+
const normalizedText = String(textValue || '').trim();
|
|
441
|
+
if (!normalizedText) {
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
return {
|
|
445
|
+
provider: 'codex',
|
|
446
|
+
kind,
|
|
447
|
+
eventType,
|
|
448
|
+
itemType: itemType || '',
|
|
449
|
+
text: normalizedText,
|
|
450
|
+
...extra
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
|
|
434
454
|
if (eventType === 'thread.started') {
|
|
435
|
-
return '[会话] Codex 已开始处理'
|
|
455
|
+
return createTraceEvent('thread', '[会话] Codex 已开始处理', {
|
|
456
|
+
phase: 'started',
|
|
457
|
+
status: 'started'
|
|
458
|
+
});
|
|
436
459
|
}
|
|
437
460
|
if (eventType === 'thread.completed') {
|
|
438
|
-
return '[会话] Codex 已完成当前任务'
|
|
461
|
+
return createTraceEvent('thread', '[会话] Codex 已完成当前任务', {
|
|
462
|
+
phase: 'completed',
|
|
463
|
+
status: 'completed'
|
|
464
|
+
});
|
|
439
465
|
}
|
|
440
466
|
if (eventType === 'turn.started') {
|
|
441
|
-
return '[回合] 开始生成响应'
|
|
467
|
+
return createTraceEvent('turn', '[回合] 开始生成响应', {
|
|
468
|
+
phase: 'started',
|
|
469
|
+
status: 'started'
|
|
470
|
+
});
|
|
442
471
|
}
|
|
443
472
|
if (eventType === 'turn.completed') {
|
|
444
|
-
return '[回合] 响应完成'
|
|
473
|
+
return createTraceEvent('turn', '[回合] 响应完成', {
|
|
474
|
+
phase: 'completed',
|
|
475
|
+
status: 'completed'
|
|
476
|
+
});
|
|
445
477
|
}
|
|
446
478
|
if (eventType === 'item.started') {
|
|
447
479
|
if (itemType === 'tool_call') {
|
|
448
|
-
return `[工具开始] ${toolName || 'tool_call'}
|
|
480
|
+
return createTraceEvent('tool', `[工具开始] ${toolName || 'tool_call'}`, {
|
|
481
|
+
phase: 'started',
|
|
482
|
+
status: pickDisplayStatus('in_progress'),
|
|
483
|
+
toolName: toolName || 'tool_call'
|
|
484
|
+
});
|
|
449
485
|
}
|
|
450
486
|
if (itemType === 'command_execution') {
|
|
451
|
-
return `[命令开始] ${commandText || 'command_execution'}
|
|
487
|
+
return createTraceEvent('command', `[命令开始] ${commandText || 'command_execution'}`, {
|
|
488
|
+
phase: 'started',
|
|
489
|
+
status: pickDisplayStatus('in_progress'),
|
|
490
|
+
command: commandText || 'command_execution'
|
|
491
|
+
});
|
|
452
492
|
}
|
|
453
493
|
if (itemType === 'mcp_tool_call') {
|
|
454
494
|
const summary = summarizeArguments(item.arguments);
|
|
455
|
-
return
|
|
456
|
-
|
|
457
|
-
|
|
495
|
+
return createTraceEvent(
|
|
496
|
+
'mcp',
|
|
497
|
+
summary
|
|
498
|
+
? `[MCP开始] ${mcpServer || 'mcp'}.${mcpTool || 'tool'} (${summary})`
|
|
499
|
+
: `[MCP开始] ${mcpServer || 'mcp'}.${mcpTool || 'tool'}`,
|
|
500
|
+
{
|
|
501
|
+
phase: 'started',
|
|
502
|
+
status: pickDisplayStatus('in_progress'),
|
|
503
|
+
server: mcpServer || 'mcp',
|
|
504
|
+
tool: mcpTool || 'tool',
|
|
505
|
+
arguments: item.arguments && typeof item.arguments === 'object' && !Array.isArray(item.arguments)
|
|
506
|
+
? item.arguments
|
|
507
|
+
: null,
|
|
508
|
+
argumentSummary: summary
|
|
509
|
+
}
|
|
510
|
+
);
|
|
458
511
|
}
|
|
459
512
|
if (itemType === 'reasoning') {
|
|
460
|
-
return text ? `[状态] ${text}` : '[状态] Codex 正在分析'
|
|
513
|
+
return createTraceEvent('status', text ? `[状态] ${text}` : '[状态] Codex 正在分析', {
|
|
514
|
+
phase: 'started',
|
|
515
|
+
status: pickDisplayStatus('in_progress'),
|
|
516
|
+
detail: text || 'Codex 正在分析'
|
|
517
|
+
});
|
|
461
518
|
}
|
|
462
519
|
if (itemType === 'agent_message') {
|
|
463
|
-
return text ? `[说明] ${text}` : '[回复] 正在生成最终答复'
|
|
520
|
+
return createTraceEvent('agent_message', text ? `[说明] ${text}` : '[回复] 正在生成最终答复', {
|
|
521
|
+
phase: 'started',
|
|
522
|
+
status: pickDisplayStatus('in_progress'),
|
|
523
|
+
detail: text || '正在生成最终答复'
|
|
524
|
+
});
|
|
464
525
|
}
|
|
465
|
-
return text ? `[事件开始] ${text}` : `[事件开始] ${itemType || eventType}
|
|
526
|
+
return createTraceEvent('event', text ? `[事件开始] ${text}` : `[事件开始] ${itemType || eventType}`, {
|
|
527
|
+
phase: 'started',
|
|
528
|
+
status: pickDisplayStatus('in_progress'),
|
|
529
|
+
detail: text || itemType || eventType
|
|
530
|
+
});
|
|
466
531
|
}
|
|
467
532
|
if (eventType === 'item.completed') {
|
|
468
533
|
if (itemType === 'tool_call') {
|
|
469
|
-
return `[工具完成] ${toolName || 'tool_call'}
|
|
534
|
+
return createTraceEvent('tool', `[工具完成] ${toolName || 'tool_call'}`, {
|
|
535
|
+
phase: 'completed',
|
|
536
|
+
status: pickDisplayStatus('completed'),
|
|
537
|
+
toolName: toolName || 'tool_call'
|
|
538
|
+
});
|
|
470
539
|
}
|
|
471
540
|
if (itemType === 'command_execution') {
|
|
472
541
|
const suffix = itemStatus || (typeof item.exit_code === 'number' ? `exit=${item.exit_code}` : 'completed');
|
|
473
|
-
return `[命令完成] ${commandText || 'command_execution'} (${suffix})
|
|
542
|
+
return createTraceEvent('command', `[命令完成] ${commandText || 'command_execution'} (${suffix})`, {
|
|
543
|
+
phase: 'completed',
|
|
544
|
+
status: pickDisplayStatus(suffix),
|
|
545
|
+
command: commandText || 'command_execution',
|
|
546
|
+
exitCode: typeof item.exit_code === 'number' ? item.exit_code : null
|
|
547
|
+
});
|
|
474
548
|
}
|
|
475
549
|
if (itemType === 'mcp_tool_call') {
|
|
476
550
|
const summary = summarizeArguments(item.arguments);
|
|
477
|
-
return
|
|
478
|
-
|
|
479
|
-
|
|
551
|
+
return createTraceEvent(
|
|
552
|
+
'mcp',
|
|
553
|
+
summary
|
|
554
|
+
? `[MCP完成] ${mcpServer || 'mcp'}.${mcpTool || 'tool'} (${summary})`
|
|
555
|
+
: `[MCP完成] ${mcpServer || 'mcp'}.${mcpTool || 'tool'}`,
|
|
556
|
+
{
|
|
557
|
+
phase: 'completed',
|
|
558
|
+
status: pickDisplayStatus('completed'),
|
|
559
|
+
server: mcpServer || 'mcp',
|
|
560
|
+
tool: mcpTool || 'tool',
|
|
561
|
+
arguments: item.arguments && typeof item.arguments === 'object' && !Array.isArray(item.arguments)
|
|
562
|
+
? item.arguments
|
|
563
|
+
: null,
|
|
564
|
+
argumentSummary: summary,
|
|
565
|
+
result: item.result !== undefined ? item.result : null,
|
|
566
|
+
error: item.error !== undefined ? item.error : null
|
|
567
|
+
}
|
|
568
|
+
);
|
|
480
569
|
}
|
|
481
570
|
if (itemType === 'reasoning') {
|
|
482
|
-
return text ? `[状态] ${text}` : ''
|
|
571
|
+
return createTraceEvent('status', text ? `[状态] ${text}` : '', {
|
|
572
|
+
phase: 'completed',
|
|
573
|
+
status: pickDisplayStatus('completed'),
|
|
574
|
+
detail: text || ''
|
|
575
|
+
});
|
|
483
576
|
}
|
|
484
577
|
if (itemType === 'agent_message') {
|
|
485
|
-
return text ? `[说明] ${text}` : '[回复] 已生成'
|
|
578
|
+
return createTraceEvent('agent_message', text ? `[说明] ${text}` : '[回复] 已生成', {
|
|
579
|
+
phase: 'completed',
|
|
580
|
+
status: pickDisplayStatus('completed'),
|
|
581
|
+
detail: text || '已生成'
|
|
582
|
+
});
|
|
486
583
|
}
|
|
487
|
-
return text ? `[事件完成] ${text}` : `[事件完成] ${itemType || eventType}
|
|
584
|
+
return createTraceEvent('event', text ? `[事件完成] ${text}` : `[事件完成] ${itemType || eventType}`, {
|
|
585
|
+
phase: 'completed',
|
|
586
|
+
status: pickDisplayStatus('completed'),
|
|
587
|
+
detail: text || itemType || eventType
|
|
588
|
+
});
|
|
488
589
|
}
|
|
489
590
|
if (eventType === 'error') {
|
|
490
|
-
return text ? `[错误] ${text}` : '[错误] Codex 返回了错误事件'
|
|
591
|
+
return createTraceEvent('error', text ? `[错误] ${text}` : '[错误] Codex 返回了错误事件', {
|
|
592
|
+
status: 'error',
|
|
593
|
+
detail: text || 'Codex 返回了错误事件'
|
|
594
|
+
});
|
|
491
595
|
}
|
|
492
596
|
|
|
493
|
-
return `[事件] ${eventType}
|
|
597
|
+
return createTraceEvent('event', `[事件] ${eventType}`, {
|
|
598
|
+
status: itemStatus || '',
|
|
599
|
+
detail: eventType
|
|
600
|
+
});
|
|
494
601
|
}
|
|
495
602
|
|
|
496
603
|
async function prepareWebAgentExecution(ctx, state, containerName, prompt) {
|
|
@@ -1432,9 +1539,14 @@ async function execAgentInWebContainerStream(ctx, state, containerName, command,
|
|
|
1432
1539
|
payload = null;
|
|
1433
1540
|
}
|
|
1434
1541
|
if (payload) {
|
|
1435
|
-
const
|
|
1436
|
-
if (
|
|
1437
|
-
onEvent({
|
|
1542
|
+
const traceEvent = prepareCodexTraceEvent(payload);
|
|
1543
|
+
if (traceEvent && traceEvent.text) {
|
|
1544
|
+
onEvent({
|
|
1545
|
+
type: 'trace',
|
|
1546
|
+
stream: 'stdout',
|
|
1547
|
+
text: traceEvent.text,
|
|
1548
|
+
traceEvent
|
|
1549
|
+
});
|
|
1438
1550
|
}
|
|
1439
1551
|
return;
|
|
1440
1552
|
}
|
|
@@ -2222,6 +2334,7 @@ async function handleWebApi(req, res, pathname, ctx, state) {
|
|
|
2222
2334
|
|
|
2223
2335
|
const { history, agentMeta, command, contextMode, resumeAttempted, resumeSucceeded, resumeError } = prepared;
|
|
2224
2336
|
const traceLines = ['[执行过程]'];
|
|
2337
|
+
const traceEvents = [];
|
|
2225
2338
|
appendWebSessionMessage(state.webHistoryDir, containerName, 'user', prompt, {
|
|
2226
2339
|
mode: 'agent',
|
|
2227
2340
|
contextMode
|
|
@@ -2253,12 +2366,16 @@ async function handleWebApi(req, res, pathname, ctx, state) {
|
|
|
2253
2366
|
onEvent: event => {
|
|
2254
2367
|
if (event && event.type === 'trace' && event.text) {
|
|
2255
2368
|
traceLines.push(String(event.text));
|
|
2369
|
+
if (event.traceEvent && typeof event.traceEvent === 'object') {
|
|
2370
|
+
traceEvents.push(event.traceEvent);
|
|
2371
|
+
}
|
|
2256
2372
|
}
|
|
2257
2373
|
sendNdjson(res, event);
|
|
2258
2374
|
}
|
|
2259
2375
|
});
|
|
2260
2376
|
traceLines.push(result.interrupted === true ? '[任务] 已停止' : '[任务] 已完成');
|
|
2261
2377
|
appendWebAgentTraceMessage(state.webHistoryDir, containerName, traceLines.join('\n'), {
|
|
2378
|
+
traceEvents,
|
|
2262
2379
|
contextMode,
|
|
2263
2380
|
resumeAttempted,
|
|
2264
2381
|
resumeSucceeded,
|
|
@@ -2282,6 +2399,7 @@ async function handleWebApi(req, res, pathname, ctx, state) {
|
|
|
2282
2399
|
} catch (e) {
|
|
2283
2400
|
traceLines.push(`[错误] ${e && e.message ? e.message : 'Agent 执行失败'}`);
|
|
2284
2401
|
appendWebAgentTraceMessage(state.webHistoryDir, containerName, traceLines.join('\n'), {
|
|
2402
|
+
traceEvents,
|
|
2285
2403
|
contextMode,
|
|
2286
2404
|
resumeAttempted,
|
|
2287
2405
|
resumeSucceeded,
|