Mike0021 commited on
Commit
216a464
·
verified ·
1 Parent(s): aa2ab8d

Parse wrapped Codex rollout records

Browse files
Files changed (1) hide show
  1. app.py +128 -4
app.py CHANGED
@@ -246,11 +246,25 @@ def _collect_timestamps(obj: dict[str, Any], timestamps: list[datetime]) -> None
246
  timestamps.append(parsed)
247
 
248
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  @lru_cache(maxsize=6)
250
  def _load_session(file_name: str) -> dict[str, Any]:
251
  path = _download_session(file_name)
252
  events: list[dict[str, Any]] = []
253
  timestamps: list[datetime] = []
 
254
  command_ids: set[str] = set()
255
  failed_commands = 0
256
  turn_completed = 0
@@ -276,10 +290,111 @@ def _load_session(file_name: str) -> dict[str, Any]:
276
  continue
277
 
278
  obj_type = obj.get("type")
 
 
279
  item = obj.get("item") if isinstance(obj.get("item"), dict) else {}
280
  item_type = item.get("type")
281
  _collect_timestamps(obj, timestamps)
282
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
283
  if obj_type == "turn.started":
284
  turn_started += 1
285
  continue
@@ -447,10 +562,12 @@ def _render_summary(data: dict[str, Any], matches: int, query: str) -> str:
447
 
448
  def _render_agent(event: dict[str, Any]) -> str:
449
  text, note = _limit_text(str(event.get("text") or ""), MAX_MESSAGE_CHARS, "message")
 
 
450
  return (
451
- '<article class="event agent-event">'
452
- '<div class="event-rail agent-rail">AGENT</div>'
453
- '<div class="bubble agent-bubble">'
454
  f'<div class="event-meta">line {_fmt_number(event["line"])}{_escape(note)}</div>'
455
  f'<div class="message-text">{_escape(text)}</div>'
456
  "</div>"
@@ -555,7 +672,7 @@ def _render_files(event: dict[str, Any]) -> str:
555
 
556
  def _render_event(event: dict[str, Any]) -> str:
557
  kind = event.get("kind")
558
- if kind == "agent":
559
  return _render_agent(event)
560
  if kind == "command":
561
  return _render_command(event)
@@ -948,6 +1065,7 @@ html, body, .gradio-container {
948
  }
949
 
950
  .agent-rail { color: var(--ct-blue); }
 
951
  .command-rail { color: var(--ct-yellow); }
952
  .usage-rail { color: var(--ct-green); }
953
  .todo-rail { color: var(--ct-cyan); }
@@ -970,6 +1088,12 @@ html, body, .gradio-container {
970
  border-left: 3px solid var(--ct-blue);
971
  }
972
 
 
 
 
 
 
 
973
  .event-meta {
974
  color: var(--ct-muted);
975
  font-family: var(--ct-mono);
 
246
  timestamps.append(parsed)
247
 
248
 
249
+ def _payload_command(payload: dict[str, Any]) -> str:
250
+ name = str(payload.get("name") or "function_call")
251
+ arguments = payload.get("arguments")
252
+ if isinstance(arguments, dict):
253
+ command = arguments.get("command")
254
+ if command:
255
+ return str(command)
256
+ return f"{name}({json.dumps(arguments, ensure_ascii=True)})"
257
+ if arguments:
258
+ return f"{name}({arguments})"
259
+ return name
260
+
261
+
262
  @lru_cache(maxsize=6)
263
  def _load_session(file_name: str) -> dict[str, Any]:
264
  path = _download_session(file_name)
265
  events: list[dict[str, Any]] = []
266
  timestamps: list[datetime] = []
267
+ pending_commands: list[str] = []
268
  command_ids: set[str] = set()
269
  failed_commands = 0
270
  turn_completed = 0
 
290
  continue
291
 
292
  obj_type = obj.get("type")
293
+ payload = obj.get("payload") if isinstance(obj.get("payload"), dict) else {}
294
+ payload_type = payload.get("type")
295
  item = obj.get("item") if isinstance(obj.get("item"), dict) else {}
296
  item_type = item.get("type")
297
  _collect_timestamps(obj, timestamps)
298
 
299
+ if obj_type == "turn_context":
300
+ turn_started += 1
301
+ continue
302
+
303
+ if obj_type == "event_msg":
304
+ if payload_type in {"agent_message", "user_message"}:
305
+ text = str(payload.get("message") or "")
306
+ is_user = payload_type == "user_message"
307
+ events.append(
308
+ {
309
+ "kind": "user" if is_user else "agent",
310
+ "role": "USER" if is_user else "AGENT",
311
+ "line": line_no,
312
+ "id": f"line-{line_no}",
313
+ "text": text,
314
+ "search": text,
315
+ }
316
+ )
317
+ continue
318
+
319
+ if payload_type == "token_count":
320
+ turn_completed += 1
321
+ usage = {key: int(payload.get(key) or 0) for key in usage_summary}
322
+ for key, value in usage.items():
323
+ usage_summary[key] += value
324
+ events.append(
325
+ {
326
+ "kind": "usage",
327
+ "line": line_no,
328
+ "usage": usage,
329
+ "search": " ".join(
330
+ [
331
+ "turn completed usage tokens",
332
+ " ".join(f"{k} {v}" for k, v in usage.items()),
333
+ ]
334
+ ),
335
+ }
336
+ )
337
+ continue
338
+
339
+ if payload_type == "item_completed" and payload.get("item_type") == "todo_list":
340
+ todos = payload.get("todos") or payload.get("items") or []
341
+ if isinstance(todos, list):
342
+ text = " ".join(str(todo.get("text") or "") for todo in todos if isinstance(todo, dict))
343
+ events.append(
344
+ {
345
+ "kind": "todo",
346
+ "line": line_no,
347
+ "id": f"line-{line_no}",
348
+ "items": todos,
349
+ "search": text,
350
+ }
351
+ )
352
+ continue
353
+
354
+ if payload_type == "patch_apply_end":
355
+ path_value = str(payload.get("path") or "patch")
356
+ events.append(
357
+ {
358
+ "kind": "files",
359
+ "line": line_no,
360
+ "id": f"line-{line_no}",
361
+ "changes": [{"kind": "patch", "path": path_value}],
362
+ "status": payload.get("status") or "",
363
+ "search": f"patch {path_value} {payload.get('status') or ''}",
364
+ }
365
+ )
366
+ continue
367
+
368
+ if obj_type == "response_item":
369
+ if payload_type == "function_call":
370
+ pending_commands.append(_payload_command(payload))
371
+ continue
372
+
373
+ if payload_type == "function_call_output":
374
+ command = pending_commands.pop(0) if pending_commands else "function_call_output"
375
+ output = _strip_ansi(payload.get("output") or "")
376
+ exit_code = payload.get("exit_code")
377
+ status = "failed" if exit_code not in (None, 0) else "completed"
378
+ label, status_class = _command_status({"status": status, "exit_code": exit_code})
379
+ if status_class == "fail":
380
+ failed_commands += 1
381
+ item_id = f"line-{line_no}"
382
+ command_ids.add(item_id)
383
+ events.append(
384
+ {
385
+ "kind": "command",
386
+ "line": line_no,
387
+ "id": item_id,
388
+ "command": command,
389
+ "output": output,
390
+ "exit_code": exit_code,
391
+ "status": label,
392
+ "status_class": status_class,
393
+ "search": " ".join([command, output, str(exit_code), label]),
394
+ }
395
+ )
396
+ continue
397
+
398
  if obj_type == "turn.started":
399
  turn_started += 1
400
  continue
 
562
 
563
  def _render_agent(event: dict[str, Any]) -> str:
564
  text, note = _limit_text(str(event.get("text") or ""), MAX_MESSAGE_CHARS, "message")
565
+ role = str(event.get("role") or "AGENT").upper()
566
+ role_class = "user" if role == "USER" else "agent"
567
  return (
568
+ f'<article class="event {role_class}-event">'
569
+ f'<div class="event-rail {role_class}-rail">{_escape(role)}</div>'
570
+ f'<div class="bubble {role_class}-bubble">'
571
  f'<div class="event-meta">line {_fmt_number(event["line"])}{_escape(note)}</div>'
572
  f'<div class="message-text">{_escape(text)}</div>'
573
  "</div>"
 
672
 
673
  def _render_event(event: dict[str, Any]) -> str:
674
  kind = event.get("kind")
675
+ if kind in {"agent", "user"}:
676
  return _render_agent(event)
677
  if kind == "command":
678
  return _render_command(event)
 
1065
  }
1066
 
1067
  .agent-rail { color: var(--ct-blue); }
1068
+ .user-rail { color: var(--ct-cyan); }
1069
  .command-rail { color: var(--ct-yellow); }
1070
  .usage-rail { color: var(--ct-green); }
1071
  .todo-rail { color: var(--ct-cyan); }
 
1088
  border-left: 3px solid var(--ct-blue);
1089
  }
1090
 
1091
+ .user-bubble {
1092
+ padding: 14px 15px;
1093
+ border-left: 3px solid var(--ct-cyan);
1094
+ background: #101820;
1095
+ }
1096
+
1097
  .event-meta {
1098
  color: var(--ct-muted);
1099
  font-family: var(--ct-mono);