Files changed (1) hide show
  1. inference.py +36 -60
inference.py CHANGED
@@ -348,44 +348,26 @@ def get_fallback_action() -> dict:
348
  # Structured logging helpers β€” [START] [STEP] [END]
349
  # ──────────────────────────────────────────────
350
 
351
- def log_start(task_id: str, metadata: Optional[dict] = None):
352
- """Emit a [START] structured log line."""
353
- entry = {"task_id": task_id}
354
- if metadata:
355
- entry.update(metadata)
356
- print(f"[START] {json.dumps(entry)}", flush=True)
357
 
358
 
359
- def log_step(task_id: str, step: int, action: dict, reward: float, done: bool, info: Optional[dict] = None):
360
- """Emit a [STEP] structured log line."""
361
  reward = rounded_open_interval_score(reward, 4)
362
- entry = {
363
- "task_id": task_id,
364
- "step": step,
365
- "action": action,
366
- "reward": reward,
367
- "done": done,
368
- }
369
- if info:
370
- entry["info"] = info
371
- print(f"[STEP] {json.dumps(entry)}", flush=True)
372
 
373
 
374
- def log_end(task_id: str, reward: float, metadata: Optional[dict] = None):
375
- """Emit an [END] structured log line."""
376
- reward = rounded_open_interval_score(reward, 4)
377
- metadata = dict(metadata or {})
378
- if not is_strict_open_interval(reward):
379
- reward = rounded_open_interval_score(0.0, 4)
380
- metadata["score_sanitized"] = True
381
-
382
- entry = {
383
- "task_id": task_id,
384
- "reward": reward,
385
- }
386
- if metadata:
387
- entry.update(metadata)
388
- print(f"[END] {json.dumps(entry)}", flush=True)
389
 
390
 
391
  # ──────────────────────────────────────────────
@@ -424,10 +406,7 @@ def run_evaluation():
424
  "count": 0,
425
  }
426
 
427
- # Emit structured task-level logs even when empty, so validators
428
- # never infer an implicit 0.0 score for a missing task.
429
- log_start(task_id, {"model": MODEL_NAME, "num_cases": 0})
430
- log_end(task_id, fallback_task_score, {"num_cases": 0, "skipped": "no_cases"})
431
  task_ended = True
432
  continue
433
 
@@ -440,13 +419,11 @@ def run_evaluation():
440
  "average": fallback_task_score,
441
  "count": 0,
442
  }
443
- log_start(task_id, {"model": MODEL_NAME, "num_cases": 0})
444
- log_end(task_id, fallback_task_score, {"num_cases": 0, "skipped": "timeout"})
445
  task_ended = True
446
  continue
447
 
448
- # ── [START] ──
449
- log_start(task_id, {"model": MODEL_NAME, "num_cases": num_cases})
450
 
451
  print(f"\n{'─' * 50}")
452
  print(f" Running {difficulty.upper()} tasks")
@@ -462,6 +439,12 @@ def run_evaluation():
462
 
463
  # Reset environment for this difficulty
464
  obs = env.reset(task_id=difficulty)
 
 
 
 
 
 
465
  print(f"\n Case {i+1}/{num_cases}: {obs.case_id}")
466
 
467
  # Get LLM action
@@ -489,17 +472,15 @@ def run_evaluation():
489
  difficulty_scores.append(score)
490
  all_scores.append(score)
491
 
 
 
492
  # ── [STEP] ──
493
  log_step(
494
- task_id=task_id,
495
- step=i + 1,
496
  action=action_dict,
497
- reward=rounded_open_interval_score(score, 4),
498
  done=done,
499
- info={
500
- "case_id": obs.case_id,
501
- "feedback": result_obs.feedback if result_obs.feedback else None,
502
- },
503
  )
504
 
505
  print(f" Score: {score:.4f}")
@@ -526,16 +507,20 @@ def run_evaluation():
526
  difficulty_scores.append(fallback_score)
527
  all_scores.append(fallback_score)
528
 
 
 
529
  # ── [STEP] with failure ──
530
  log_step(
531
- task_id=task_id,
532
- step=i + 1,
533
  action=action_dict,
534
  reward=fallback_score,
535
  done=True,
536
- info={"error": str(e)},
537
  )
538
 
 
 
 
539
  # Rate limiting
540
  time.sleep(0.5)
541
 
@@ -548,9 +533,6 @@ def run_evaluation():
548
  "count": len(difficulty_scores),
549
  }
550
  print(f"\n {difficulty.upper()} Average: {avg:.4f} ({len(difficulty_scores)} cases)")
551
-
552
- # ── [END] ──
553
- log_end(task_id, normalized_avg, {"num_cases": len(difficulty_scores)})
554
  task_ended = True
555
  else:
556
  # If a tier is interrupted before any scored step, still emit
@@ -562,7 +544,6 @@ def run_evaluation():
562
  "count": 0,
563
  }
564
  print(f"\n {difficulty.upper()} Average: {fallback_task_score:.4f} (0 cases)")
565
- log_end(task_id, fallback_task_score, {"num_cases": 0, "skipped": "no_scored_cases"})
566
  task_ended = True
567
  except Exception as difficulty_error:
568
  print(f"\n βœ— Difficulty '{difficulty}' failed unexpectedly: {difficulty_error}")
@@ -573,11 +554,6 @@ def run_evaluation():
573
  "count": 0,
574
  }
575
  if not task_ended:
576
- log_end(
577
- task_id,
578
- fallback_task_score,
579
- {"num_cases": 0, "skipped": "difficulty_exception", "error": str(difficulty_error)},
580
- )
581
  task_ended = True
582
 
583
  # Final summary
 
348
  # Structured logging helpers β€” [START] [STEP] [END]
349
  # ──────────────────────────────────────────────
350
 
351
+ def log_start(task_name: str, env_name: str, model_name: str):
352
+ """Emit a [START] structured log line according to Hackathon rules."""
353
+ print(f"[START] task={task_name} env={env_name} model={model_name}", flush=True)
 
 
 
354
 
355
 
356
+ def log_step(step_idx: int, action: dict, reward: float, done: bool, error_msg: Optional[str] = None):
357
+ """Emit a [STEP] structured log line according to Hackathon rules."""
358
  reward = rounded_open_interval_score(reward, 4)
359
+ action_str = json.dumps(action, separators=(',', ':')).replace('\n', '')
360
+ err_str = f'"{error_msg}"' if error_msg else "null"
361
+ done_str = "true" if done else "false"
362
+ print(f"[STEP] step={step_idx} action={action_str} reward={reward:.2f} done={done_str} error={err_str}", flush=True)
 
 
 
 
 
 
363
 
364
 
365
+ def log_end(success: bool, steps: int, rewards: list[float]):
366
+ """Emit an [END] structured log line according to Hackathon rules."""
367
+ succ_str = "true" if success else "false"
368
+ # Ensure any printed rewards strictly match the rules
369
+ rews_str = ",".join([f"{rounded_open_interval_score(r, 4):.2f}" for r in rewards])
370
+ print(f"[END] success={succ_str} steps={steps} rewards={rews_str}", flush=True)
 
 
 
 
 
 
 
 
 
371
 
372
 
373
  # ──────────────────────────────────────────────
 
406
  "count": 0,
407
  }
408
 
409
+ # We skip logging start/end here because the validator wants them per-episode.
 
 
 
410
  task_ended = True
411
  continue
412
 
 
419
  "average": fallback_task_score,
420
  "count": 0,
421
  }
422
+ # Skipped due to timeout
 
423
  task_ended = True
424
  continue
425
 
426
+ # Episodes start within the loop below
 
427
 
428
  print(f"\n{'─' * 50}")
429
  print(f" Running {difficulty.upper()} tasks")
 
439
 
440
  # Reset environment for this difficulty
441
  obs = env.reset(task_id=difficulty)
442
+
443
+ case_name = obs.case_id if obs.case_id else f"{difficulty}_{i+1}"
444
+
445
+ # ── [START] EPISODE ──
446
+ log_start(task_name=case_name, env_name="medcoderl", model_name=MODEL_NAME)
447
+ episode_rewards = []
448
  print(f"\n Case {i+1}/{num_cases}: {obs.case_id}")
449
 
450
  # Get LLM action
 
472
  difficulty_scores.append(score)
473
  all_scores.append(score)
474
 
475
+ episode_rewards.append(score)
476
+
477
  # ── [STEP] ──
478
  log_step(
479
+ step_idx=1,
 
480
  action=action_dict,
481
+ reward=score,
482
  done=done,
483
+ error_msg=None
 
 
 
484
  )
485
 
486
  print(f" Score: {score:.4f}")
 
507
  difficulty_scores.append(fallback_score)
508
  all_scores.append(fallback_score)
509
 
510
+ episode_rewards.append(fallback_score)
511
+
512
  # ── [STEP] with failure ──
513
  log_step(
514
+ step_idx=1,
 
515
  action=action_dict,
516
  reward=fallback_score,
517
  done=True,
518
+ error_msg=str(e)
519
  )
520
 
521
+ # ── [END] EPISODE ──
522
+ log_end(success=True, steps=1, rewards=episode_rewards)
523
+
524
  # Rate limiting
525
  time.sleep(0.5)
526
 
 
533
  "count": len(difficulty_scores),
534
  }
535
  print(f"\n {difficulty.upper()} Average: {avg:.4f} ({len(difficulty_scores)} cases)")
 
 
 
536
  task_ended = True
537
  else:
538
  # If a tier is interrupted before any scored step, still emit
 
544
  "count": 0,
545
  }
546
  print(f"\n {difficulty.upper()} Average: {fallback_task_score:.4f} (0 cases)")
 
547
  task_ended = True
548
  except Exception as difficulty_error:
549
  print(f"\n βœ— Difficulty '{difficulty}' failed unexpectedly: {difficulty_error}")
 
554
  "count": 0,
555
  }
556
  if not task_ended:
 
 
 
 
 
557
  task_ended = True
558
 
559
  # Final summary