@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.
@@ -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;
@@ -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 (shouldRenderMarkdown) {
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 prepareCodexTraceDisplayLine(payload) {
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 summary
456
- ? `[MCP开始] ${mcpServer || 'mcp'}.${mcpTool || 'tool'} (${summary})`
457
- : `[MCP开始] ${mcpServer || 'mcp'}.${mcpTool || 'tool'}`;
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 summary
478
- ? `[MCP完成] ${mcpServer || 'mcp'}.${mcpTool || 'tool'} (${summary})`
479
- : `[MCP完成] ${mcpServer || 'mcp'}.${mcpTool || 'tool'}`;
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 display = prepareCodexTraceDisplayLine(payload);
1436
- if (display) {
1437
- onEvent({ type: 'trace', stream: 'stdout', text: display });
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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xcanwin/manyoyo",
3
- "version": "5.6.9",
3
+ "version": "5.6.10",
4
4
  "imageVersion": "1.9.0-common",
5
5
  "playwrightCliVersion": "0.1.1",
6
6
  "description": "AI Agent CLI Security Sandbox for Docker and Podman",