Rishav commited on
Commit
a0d2d1a
·
1 Parent(s): 0f8b9de

Add central procurement and subagent replay

Browse files
README.md CHANGED
@@ -54,6 +54,7 @@ It does **not** observe raw customer orders.
54
 
55
  It can act by:
56
 
 
57
  - sending stock from the central depot to warehouses
58
  - approving warehouse offer/request matches
59
  - proposing direct inventory transfers
@@ -77,9 +78,9 @@ Warehouses handle their own local fulfillment. They decide which local orders to
77
 
78
  ### Central Depot
79
 
80
- The central depot has finite inventory and limited trucks. It can supply warehouses, but every shipment consumes stock and truck capacity.
81
 
82
- This makes holding inventory a real strategic choice.
83
 
84
  ## Items
85
 
@@ -107,20 +108,22 @@ Each task is generated deterministically from a seed. The same task and seed rec
107
  Each round works like this:
108
 
109
  1. Depot trucks and local drivers return if their trips are complete.
110
- 2. Warehouses publish compressed demand reports and market signals.
111
- 3. The central orchestrator submits an action.
112
- 4. Depot replenishments consume depot stock and trucks.
113
- 5. Approved offer matches become proposed warehouse transfers.
114
- 6. Warehouses accept or reject transfers based on hidden local incentives.
115
- 7. Local warehouses fulfill their own local customer orders.
116
- 8. Missed or late demand is penalized.
117
- 9. Reward components and diagnostics are returned.
 
 
118
 
119
  ## Observation
120
 
121
  The central policy receives structured JSON containing:
122
 
123
- - `central_depot`: depot inventory, available trucks, returning trucks, replenishment cap
124
  - `warehouses`: inventory, driver availability, route costs, public message
125
  - `demand_reports`: compressed truthful reports of requested, forecast, missed, and at-risk units
126
  - `market_signals`: inventory offers and requests
@@ -135,6 +138,12 @@ The central orchestrator returns strict JSON:
135
 
136
  ```json
137
  {
 
 
 
 
 
 
138
  "central_replenishments": [
139
  {
140
  "to_warehouse": "north",
@@ -165,7 +174,7 @@ The central orchestrator returns strict JSON:
165
  }
166
  ```
167
 
168
- The most important actions today are `central_replenishments`, `inventory_transfers`, and `offer_matches`.
169
 
170
  ## Reward
171
 
@@ -177,8 +186,10 @@ step_reward =
177
  + accepted_trade_bonus
178
  + coalition_bonus
179
  + central_replenishment_bonus
 
180
  + priority_alignment_bonus
181
  - delivery_cost
 
182
  - central_replenishment_cost
183
  - transfer_cost
184
  - stockout_penalty
 
54
 
55
  It can act by:
56
 
57
+ - buying new inventory into the central depot, with procurement caps and lead time
58
  - sending stock from the central depot to warehouses
59
  - approving warehouse offer/request matches
60
  - proposing direct inventory transfers
 
78
 
79
  ### Central Depot
80
 
81
+ The central depot has finite inventory, limited trucks, and a limited procurement budget each round. It can buy new stock, but purchases arrive after a lead time. It can also supply warehouses, but every shipment consumes depot stock and truck capacity.
82
 
83
+ This makes forecasting and holding inventory real strategic choices.
84
 
85
  ## Items
86
 
 
108
  Each round works like this:
109
 
110
  1. Depot trucks and local drivers return if their trips are complete.
111
+ 2. Previously purchased depot inventory arrives if its lead time has elapsed.
112
+ 3. Warehouses publish compressed demand reports and market signals.
113
+ 4. The central orchestrator submits an action.
114
+ 5. Depot procurements buy future central stock.
115
+ 6. Depot replenishments consume depot stock and trucks.
116
+ 7. Approved offer matches become proposed warehouse transfers.
117
+ 8. Warehouses accept or reject transfers based on hidden local incentives.
118
+ 9. Local warehouses fulfill their own local customer orders.
119
+ 10. Missed or late demand is penalized.
120
+ 11. Reward components and diagnostics are returned.
121
 
122
  ## Observation
123
 
124
  The central policy receives structured JSON containing:
125
 
126
+ - `central_depot`: depot inventory, available trucks, returning trucks, inbound purchases, shipment cap, procurement cap
127
  - `warehouses`: inventory, driver availability, route costs, public message
128
  - `demand_reports`: compressed truthful reports of requested, forecast, missed, and at-risk units
129
  - `market_signals`: inventory offers and requests
 
138
 
139
  ```json
140
  {
141
+ "central_procurements": [
142
+ {
143
+ "sku": "insulin_pack",
144
+ "units": 3
145
+ }
146
+ ],
147
  "central_replenishments": [
148
  {
149
  "to_warehouse": "north",
 
174
  }
175
  ```
176
 
177
+ The most important actions today are `central_procurements`, `central_replenishments`, `inventory_transfers`, and `offer_matches`.
178
 
179
  ## Reward
180
 
 
186
  + accepted_trade_bonus
187
  + coalition_bonus
188
  + central_replenishment_bonus
189
+ + strategic_procurement_bonus
190
  + priority_alignment_bonus
191
  - delivery_cost
192
+ - central_procurement_cost
193
  - central_replenishment_cost
194
  - transfer_cost
195
  - stockout_penalty
inference.py CHANGED
@@ -31,9 +31,10 @@ SYSTEM_PROMPT = (
31
  "You are the central orchestrator in a multi-agent warehouse network. "
32
  "Warehouses publish market signals, but their deeper incentives are hidden and must be inferred from behavior. "
33
  "You do not see individual customer orders; local warehouse agents handle local fulfillment. "
34
- "Return JSON only with optional keys central_replenishments, inventory_transfers, offer_matches, "
35
  "priority_policy, defer_orders, and coalition_deals. "
36
- "Use central_replenishments for limited depot-to-warehouse restock and offer_matches to pair compatible inventory offers and requests; use direct transfers only "
 
37
  "when the compensation is likely to be accepted. Optimize global welfare while respecting local incentives, "
38
  "stockouts, delivery cost, fairness, and rejected-trade risk."
39
  )
 
31
  "You are the central orchestrator in a multi-agent warehouse network. "
32
  "Warehouses publish market signals, but their deeper incentives are hidden and must be inferred from behavior. "
33
  "You do not see individual customer orders; local warehouse agents handle local fulfillment. "
34
+ "Return JSON only with optional keys central_procurements, central_replenishments, inventory_transfers, offer_matches, "
35
  "priority_policy, defer_orders, and coalition_deals. "
36
+ "Use central_procurements to buy future depot stock when depot inventory is running low, "
37
+ "central_replenishments for limited depot-to-warehouse restock, and offer_matches to pair compatible inventory offers and requests; use direct transfers only "
38
  "when the compensation is likely to be accepted. Optimize global welfare while respecting local incentives, "
39
  "stockouts, delivery cost, fairness, and rejected-trade risk."
40
  )
results/blackbox_codex_subagent_episode.json ADDED
The diff for this file is too large to render. See raw diff
 
results/policy_eval.json CHANGED
@@ -1,7 +1,7 @@
1
  {
2
  "summary": {
3
  "no_op": {
4
- "mean_score": 0.0718,
5
  "mean_reward": -337.644,
6
  "episodes": 12
7
  },
@@ -11,13 +11,13 @@
11
  "episodes": 12
12
  },
13
  "negotiation_heuristic": {
14
- "mean_score": 0.4011,
15
- "mean_reward": -123.403,
16
  "episodes": 12
17
  },
18
  "privileged_reference": {
19
  "mean_score": 0.9999,
20
- "mean_reward": -54.93,
21
  "episodes": 12
22
  }
23
  },
@@ -30,8 +30,8 @@
30
  "raw_reward": 80.18,
31
  "score": 0.0001,
32
  "baseline_reward": 179.02,
33
- "heuristic_reward": 228.488,
34
- "target_reward": 238.488,
35
  "step_rewards": [
36
  19.26,
37
  17.0,
@@ -178,8 +178,8 @@
178
  "raw_reward": -146.63,
179
  "score": 0.0001,
180
  "baseline_reward": 62.465,
181
- "heuristic_reward": 62.465,
182
- "target_reward": 82.465,
183
  "step_rewards": [
184
  33.2,
185
  -7.8,
@@ -220,8 +220,8 @@
220
  "raw_reward": -129.385,
221
  "score": 0.0001,
222
  "baseline_reward": 780.6,
223
- "heuristic_reward": 922.507,
224
- "target_reward": 932.507,
225
  "step_rewards": [
226
  35.065,
227
  70.525,
@@ -262,8 +262,8 @@
262
  "raw_reward": -136.07,
263
  "score": 0.0001,
264
  "baseline_reward": -29.105,
265
- "heuristic_reward": 101.619,
266
- "target_reward": 111.619,
267
  "step_rewards": [
268
  49.165,
269
  10.275,
@@ -304,7 +304,7 @@
304
  "raw_reward": 62.11,
305
  "score": 0.0001,
306
  "baseline_reward": 126.78,
307
- "heuristic_reward": 116.931,
308
  "target_reward": 146.78,
309
  "step_rewards": [
310
  0.99,
@@ -346,8 +346,8 @@
346
  "raw_reward": -2242.475,
347
  "score": 0.0001,
348
  "baseline_reward": -1832.7,
349
- "heuristic_reward": -1584.904,
350
- "target_reward": -1574.904,
351
  "step_rewards": [
352
  28.46,
353
  4.99,
@@ -396,10 +396,10 @@
396
  "internal_task_id": "v1_crisis_coalition",
397
  "seed": 603,
398
  "raw_reward": -954.785,
399
- "score": 0.8607,
400
  "baseline_reward": -1520.675,
401
- "heuristic_reward": -1495.497,
402
- "target_reward": -857.625,
403
  "step_rewards": [
404
  25.15,
405
  53.48,
@@ -450,8 +450,8 @@
450
  "raw_reward": -770.235,
451
  "score": 0.0001,
452
  "baseline_reward": -616.805,
453
- "heuristic_reward": -476.96,
454
- "target_reward": -466.675,
455
  "step_rewards": [
456
  25.61,
457
  50.76,
@@ -502,8 +502,8 @@
502
  "raw_reward": -1025.74,
503
  "score": 0.0001,
504
  "baseline_reward": -878.21,
505
- "heuristic_reward": -1021.982,
506
- "target_reward": -858.21,
507
  "step_rewards": [
508
  72.295,
509
  24.84,
@@ -556,8 +556,8 @@
556
  "raw_reward": 179.02,
557
  "score": 0.05,
558
  "baseline_reward": 179.02,
559
- "heuristic_reward": 228.488,
560
- "target_reward": 238.488,
561
  "step_rewards": [
562
  19.26,
563
  17.0,
@@ -704,8 +704,8 @@
704
  "raw_reward": 62.465,
705
  "score": 0.05,
706
  "baseline_reward": 62.465,
707
- "heuristic_reward": 62.465,
708
- "target_reward": 82.465,
709
  "step_rewards": [
710
  33.2,
711
  -7.8,
@@ -746,8 +746,8 @@
746
  "raw_reward": 780.6,
747
  "score": 0.05,
748
  "baseline_reward": 780.6,
749
- "heuristic_reward": 922.507,
750
- "target_reward": 932.507,
751
  "step_rewards": [
752
  31.055,
753
  70.415,
@@ -788,8 +788,8 @@
788
  "raw_reward": -29.105,
789
  "score": 0.05,
790
  "baseline_reward": -29.105,
791
- "heuristic_reward": 101.619,
792
- "target_reward": 111.619,
793
  "step_rewards": [
794
  49.165,
795
  10.275,
@@ -830,7 +830,7 @@
830
  "raw_reward": 126.78,
831
  "score": 0.05,
832
  "baseline_reward": 126.78,
833
- "heuristic_reward": 116.931,
834
  "target_reward": 146.78,
835
  "step_rewards": [
836
  0.99,
@@ -872,8 +872,8 @@
872
  "raw_reward": -1832.7,
873
  "score": 0.05,
874
  "baseline_reward": -1832.7,
875
- "heuristic_reward": -1584.904,
876
- "target_reward": -1574.904,
877
  "step_rewards": [
878
  94.155,
879
  -11.865,
@@ -924,8 +924,8 @@
924
  "raw_reward": -1520.675,
925
  "score": 0.05,
926
  "baseline_reward": -1520.675,
927
- "heuristic_reward": -1495.497,
928
- "target_reward": -857.625,
929
  "step_rewards": [
930
  89.685,
931
  23.305,
@@ -976,8 +976,8 @@
976
  "raw_reward": -616.805,
977
  "score": 0.05,
978
  "baseline_reward": -616.805,
979
- "heuristic_reward": -476.96,
980
- "target_reward": -466.675,
981
  "step_rewards": [
982
  21.58,
983
  50.63,
@@ -1028,8 +1028,8 @@
1028
  "raw_reward": -878.21,
1029
  "score": 0.05,
1030
  "baseline_reward": -878.21,
1031
- "heuristic_reward": -1021.982,
1032
- "target_reward": -858.21,
1033
  "step_rewards": [
1034
  66.25,
1035
  24.645,
@@ -1079,11 +1079,11 @@
1079
  "task_id": "cooperative_restock",
1080
  "internal_task_id": "v1_cooperative_restock",
1081
  "seed": 401,
1082
- "raw_reward": 228.488,
1083
- "score": 0.8402,
1084
  "baseline_reward": 179.02,
1085
- "heuristic_reward": 228.488,
1086
- "target_reward": 238.488,
1087
  "step_rewards": [
1088
  19.26,
1089
  17.0,
@@ -1101,15 +1101,15 @@
1101
  -25.2,
1102
  4.78,
1103
  -10.33,
1104
- 10.08,
1105
  27.77,
1106
  1.84,
1107
- 3.66,
1108
- -18.68,
1109
- -27.41,
1110
- 36.006,
1111
- -76.224,
1112
- 13.686
1113
  ]
1114
  },
1115
  {
@@ -1227,11 +1227,11 @@
1227
  "task_id": "scarcity_negotiation",
1228
  "internal_task_id": "v1_scarcity_negotiation",
1229
  "seed": 501,
1230
- "raw_reward": 62.465,
1231
- "score": 0.05,
1232
  "baseline_reward": 62.465,
1233
- "heuristic_reward": 62.465,
1234
- "target_reward": 82.465,
1235
  "step_rewards": [
1236
  33.2,
1237
  -7.8,
@@ -1249,31 +1249,31 @@
1249
  -23.455,
1250
  -29.15,
1251
  -33.145,
1252
- 22.965,
1253
  -39.085,
1254
- 38.06,
1255
  71.09,
1256
- -0.755,
1257
  -56.44,
1258
  61.38,
1259
  -22.72,
1260
- -37.62,
1261
- -50.165,
1262
- -54.215,
1263
- -66.715,
1264
- -56.235,
1265
- -34.605
1266
  ]
1267
  },
1268
  {
1269
  "task_id": "scarcity_negotiation",
1270
  "internal_task_id": "v1_scarcity_negotiation",
1271
  "seed": 503,
1272
- "raw_reward": 922.507,
1273
- "score": 0.9374,
1274
  "baseline_reward": 780.6,
1275
- "heuristic_reward": 922.507,
1276
- "target_reward": 932.507,
1277
  "step_rewards": [
1278
  31.055,
1279
  70.415,
@@ -1295,27 +1295,27 @@
1295
  11.485,
1296
  105.698,
1297
  3.641,
1298
- 74.38,
1299
  14.69,
1300
  1.29,
1301
  21.501,
1302
- 1.601,
1303
- 59.166,
1304
- 71.626,
1305
- -44.892,
1306
- -23.567,
1307
- -4.57
1308
  ]
1309
  },
1310
  {
1311
  "task_id": "scarcity_negotiation",
1312
  "internal_task_id": "v1_scarcity_negotiation",
1313
  "seed": 505,
1314
- "raw_reward": 101.619,
1315
- "score": 0.9324,
1316
  "baseline_reward": -29.105,
1317
- "heuristic_reward": 101.619,
1318
- "target_reward": 111.619,
1319
  "step_rewards": [
1320
  49.165,
1321
  10.275,
@@ -1337,26 +1337,26 @@
1337
  -3.491,
1338
  29.508,
1339
  -7.837,
1340
- -10.772,
1341
  70.998,
1342
  19.108,
1343
  -8.292,
1344
  -42.892,
1345
- 25.668,
1346
  75.658,
1347
- -44.347,
1348
- -59.142,
1349
- 34.813
1350
  ]
1351
  },
1352
  {
1353
  "task_id": "scarcity_negotiation",
1354
  "internal_task_id": "v1_scarcity_negotiation",
1355
  "seed": 507,
1356
- "raw_reward": 116.931,
1357
  "score": 0.0001,
1358
  "baseline_reward": 126.78,
1359
- "heuristic_reward": 116.931,
1360
  "target_reward": 146.78,
1361
  "step_rewards": [
1362
  0.99,
@@ -1379,27 +1379,27 @@
1379
  -14.11,
1380
  21.965,
1381
  -46.635,
1382
- 3.095,
1383
  36.235,
1384
- 31.895,
1385
  -35.985,
1386
- -40.125,
1387
  -63.69,
1388
  -13.795,
1389
  53.758,
1390
- -45.692,
1391
- -5.077
1392
  ]
1393
  },
1394
  {
1395
  "task_id": "crisis_coalition",
1396
  "internal_task_id": "v1_crisis_coalition",
1397
  "seed": 601,
1398
- "raw_reward": -1584.904,
1399
- "score": 0.9631,
1400
  "baseline_reward": -1832.7,
1401
- "heuristic_reward": -1584.904,
1402
- "target_reward": -1574.904,
1403
  "step_rewards": [
1404
  94.155,
1405
  -11.865,
@@ -1410,48 +1410,48 @@
1410
  -11.296,
1411
  5.93,
1412
  34.015,
1413
- -34.975,
1414
  -70.91,
1415
- -24.585,
1416
  -32.325,
1417
  -80.325,
1418
  -23.46,
1419
  -67.055,
1420
  -21.26,
1421
  -25.57,
1422
- -60.605,
1423
- 36.705,
1424
- -11.165,
1425
- -50.535,
1426
- 22.395,
1427
- -19.615,
1428
- -172.81,
1429
- -93.61,
1430
- -17.97,
1431
- -79.48,
1432
- -212.68,
1433
- -89.935,
1434
- -19.09,
1435
- -48.815,
1436
- -58.965,
1437
- -41.931,
1438
- -126.371,
1439
- -28.816,
1440
- -61.751,
1441
- -160.301,
1442
- -75.251,
1443
- -109.711
1444
  ]
1445
  },
1446
  {
1447
  "task_id": "crisis_coalition",
1448
  "internal_task_id": "v1_crisis_coalition",
1449
  "seed": 603,
1450
- "raw_reward": -1495.497,
1451
- "score": 0.0861,
1452
  "baseline_reward": -1520.675,
1453
- "heuristic_reward": -1495.497,
1454
- "target_reward": -857.625,
1455
  "step_rewards": [
1456
  89.685,
1457
  23.305,
@@ -1461,49 +1461,49 @@
1461
  -16.79,
1462
  -19.78,
1463
  -82.715,
1464
- -74.615,
1465
  -51.305,
1466
  -24.705,
1467
  -15.38,
1468
- -157.73,
1469
- -42.785,
1470
- -101.855,
1471
- 23.645,
1472
- -84.485,
1473
- 5.33,
1474
- -7.675,
1475
- -47.15,
1476
- -42.635,
1477
- 14.125,
1478
- 27.515,
1479
- -5.0,
1480
- -65.975,
1481
- -16.16,
1482
- -57.26,
1483
- 6.965,
1484
- -85.035,
1485
- -22.345,
1486
- -99.53,
1487
- -29.65,
1488
- -45.085,
1489
- -147.47,
1490
- -13.252,
1491
- -141.637,
1492
- -47.332,
1493
- -93.332,
1494
- 56.5,
1495
- -75.532
1496
  ]
1497
  },
1498
  {
1499
  "task_id": "crisis_coalition",
1500
  "internal_task_id": "v1_crisis_coalition",
1501
  "seed": 605,
1502
- "raw_reward": -476.96,
1503
- "score": 0.9348,
1504
  "baseline_reward": -616.805,
1505
- "heuristic_reward": -476.96,
1506
- "target_reward": -466.675,
1507
  "step_rewards": [
1508
  21.58,
1509
  50.63,
@@ -1522,40 +1522,40 @@
1522
  74.566,
1523
  26.691,
1524
  -13.224,
1525
- 12.856,
1526
  18.76,
1527
  -59.39,
1528
- 48.84,
1529
  72.685,
1530
- 11.48,
1531
- -49.455,
1532
- 5.16,
1533
- 8.945,
1534
- -59.99,
1535
- -91.985,
1536
- -14.755,
1537
- -63.755,
1538
- -25.56,
1539
- -59.805,
1540
- -97.88,
1541
- -154.57,
1542
- 13.565,
1543
- -35.51,
1544
- -173.27,
1545
- -53.47,
1546
- -30.405,
1547
- -55.09
1548
  ]
1549
  },
1550
  {
1551
  "task_id": "crisis_coalition",
1552
  "internal_task_id": "v1_crisis_coalition",
1553
  "seed": 607,
1554
- "raw_reward": -1021.982,
1555
- "score": 0.0001,
1556
  "baseline_reward": -878.21,
1557
- "heuristic_reward": -1021.982,
1558
- "target_reward": -858.21,
1559
  "step_rewards": [
1560
  66.25,
1561
  24.645,
@@ -1565,38 +1565,38 @@
1565
  12.64,
1566
  72.245,
1567
  -6.89,
1568
- 6.695,
1569
  40.235,
1570
  -32.635,
1571
  57.026,
1572
- -46.709,
1573
- 2.456,
1574
- -1.534,
1575
- -45.829,
1576
- -41.954,
1577
- -10.629,
1578
- -65.679,
1579
- -86.744,
1580
- 73.271,
1581
- -77.164,
1582
- -95.839,
1583
- -27.42,
1584
- -68.175,
1585
- -19.605,
1586
- -92.905,
1587
- -28.249,
1588
- -126.945,
1589
- -72.52,
1590
- 14.21,
1591
- -105.155,
1592
- 12.18,
1593
- 4.005,
1594
- -78.18,
1595
- -162.49,
1596
- -26.67,
1597
- 2.69,
1598
- -96.615,
1599
- -44.7
1600
  ]
1601
  }
1602
  ],
@@ -1605,11 +1605,11 @@
1605
  "task_id": "cooperative_restock",
1606
  "internal_task_id": "v1_cooperative_restock",
1607
  "seed": 401,
1608
- "raw_reward": 228.48800000000008,
1609
  "score": 0.9999,
1610
  "baseline_reward": 179.02,
1611
- "heuristic_reward": 228.488,
1612
- "target_reward": 228.48800000000008,
1613
  "step_rewards": []
1614
  },
1615
  {
@@ -1649,33 +1649,33 @@
1649
  "task_id": "scarcity_negotiation",
1650
  "internal_task_id": "v1_scarcity_negotiation",
1651
  "seed": 501,
1652
- "raw_reward": 62.464999999999876,
1653
  "score": 0.9999,
1654
  "baseline_reward": 62.465,
1655
- "heuristic_reward": 62.465,
1656
- "target_reward": 62.464999999999876,
1657
  "step_rewards": []
1658
  },
1659
  {
1660
  "task_id": "scarcity_negotiation",
1661
  "internal_task_id": "v1_scarcity_negotiation",
1662
  "seed": 503,
1663
- "raw_reward": 922.5067999999998,
1664
  "score": 0.9999,
1665
  "baseline_reward": 780.6,
1666
- "heuristic_reward": 922.507,
1667
- "target_reward": 922.5067999999998,
1668
  "step_rewards": []
1669
  },
1670
  {
1671
  "task_id": "scarcity_negotiation",
1672
  "internal_task_id": "v1_scarcity_negotiation",
1673
  "seed": 505,
1674
- "raw_reward": 101.61859999999996,
1675
  "score": 0.9999,
1676
  "baseline_reward": -29.105,
1677
- "heuristic_reward": 101.619,
1678
- "target_reward": 101.61859999999996,
1679
  "step_rewards": []
1680
  },
1681
  {
@@ -1685,7 +1685,7 @@
1685
  "raw_reward": 135.1099999999999,
1686
  "score": 0.9999,
1687
  "baseline_reward": 126.78,
1688
- "heuristic_reward": 116.931,
1689
  "target_reward": 135.1099999999999,
1690
  "step_rewards": []
1691
  },
@@ -1693,44 +1693,44 @@
1693
  "task_id": "crisis_coalition",
1694
  "internal_task_id": "v1_crisis_coalition",
1695
  "seed": 601,
1696
- "raw_reward": -1584.904,
1697
  "score": 0.9999,
1698
  "baseline_reward": -1832.7,
1699
- "heuristic_reward": -1584.904,
1700
- "target_reward": -1584.904,
1701
  "step_rewards": []
1702
  },
1703
  {
1704
  "task_id": "crisis_coalition",
1705
  "internal_task_id": "v1_crisis_coalition",
1706
  "seed": 603,
1707
- "raw_reward": -857.6249999999999,
1708
  "score": 0.9999,
1709
  "baseline_reward": -1520.675,
1710
- "heuristic_reward": -1495.497,
1711
- "target_reward": -857.6249999999999,
1712
  "step_rewards": []
1713
  },
1714
  {
1715
  "task_id": "crisis_coalition",
1716
  "internal_task_id": "v1_crisis_coalition",
1717
  "seed": 605,
1718
- "raw_reward": -466.67499999999984,
1719
  "score": 0.9999,
1720
  "baseline_reward": -616.805,
1721
- "heuristic_reward": -476.96,
1722
- "target_reward": -466.67499999999984,
1723
  "step_rewards": []
1724
  },
1725
  {
1726
  "task_id": "crisis_coalition",
1727
  "internal_task_id": "v1_crisis_coalition",
1728
  "seed": 607,
1729
- "raw_reward": -876.7949999999996,
1730
  "score": 0.9999,
1731
  "baseline_reward": -878.21,
1732
- "heuristic_reward": -1021.982,
1733
- "target_reward": -876.7949999999996,
1734
  "step_rewards": []
1735
  }
1736
  ]
 
1
  {
2
  "summary": {
3
  "no_op": {
4
+ "mean_score": 0.067,
5
  "mean_reward": -337.644,
6
  "episodes": 12
7
  },
 
11
  "episodes": 12
12
  },
13
  "negotiation_heuristic": {
14
+ "mean_score": 0.5335,
15
+ "mean_reward": -21.661,
16
  "episodes": 12
17
  },
18
  "privileged_reference": {
19
  "mean_score": 0.9999,
20
+ "mean_reward": 19.509,
21
  "episodes": 12
22
  }
23
  },
 
30
  "raw_reward": 80.18,
31
  "score": 0.0001,
32
  "baseline_reward": 179.02,
33
+ "heuristic_reward": 267.48,
34
+ "target_reward": 277.48,
35
  "step_rewards": [
36
  19.26,
37
  17.0,
 
178
  "raw_reward": -146.63,
179
  "score": 0.0001,
180
  "baseline_reward": 62.465,
181
+ "heuristic_reward": 86.065,
182
+ "target_reward": 96.065,
183
  "step_rewards": [
184
  33.2,
185
  -7.8,
 
220
  "raw_reward": -129.385,
221
  "score": 0.0001,
222
  "baseline_reward": 780.6,
223
+ "heuristic_reward": 945.868,
224
+ "target_reward": 955.868,
225
  "step_rewards": [
226
  35.065,
227
  70.525,
 
262
  "raw_reward": -136.07,
263
  "score": 0.0001,
264
  "baseline_reward": -29.105,
265
+ "heuristic_reward": 142.784,
266
+ "target_reward": 152.784,
267
  "step_rewards": [
268
  49.165,
269
  10.275,
 
304
  "raw_reward": 62.11,
305
  "score": 0.0001,
306
  "baseline_reward": 126.78,
307
+ "heuristic_reward": 83.171,
308
  "target_reward": 146.78,
309
  "step_rewards": [
310
  0.99,
 
346
  "raw_reward": -2242.475,
347
  "score": 0.0001,
348
  "baseline_reward": -1832.7,
349
+ "heuristic_reward": -1275.212,
350
+ "target_reward": -1265.212,
351
  "step_rewards": [
352
  28.46,
353
  4.99,
 
396
  "internal_task_id": "v1_crisis_coalition",
397
  "seed": 603,
398
  "raw_reward": -954.785,
399
+ "score": 0.803,
400
  "baseline_reward": -1520.675,
401
+ "heuristic_reward": -1037.244,
402
+ "target_reward": -806.805,
403
  "step_rewards": [
404
  25.15,
405
  53.48,
 
450
  "raw_reward": -770.235,
451
  "score": 0.0001,
452
  "baseline_reward": -616.805,
453
+ "heuristic_reward": -587.46,
454
+ "target_reward": -385.957,
455
  "step_rewards": [
456
  25.61,
457
  50.76,
 
502
  "raw_reward": -1025.74,
503
  "score": 0.0001,
504
  "baseline_reward": -878.21,
505
+ "heuristic_reward": -551.885,
506
+ "target_reward": -541.885,
507
  "step_rewards": [
508
  72.295,
509
  24.84,
 
556
  "raw_reward": 179.02,
557
  "score": 0.05,
558
  "baseline_reward": 179.02,
559
+ "heuristic_reward": 267.48,
560
+ "target_reward": 277.48,
561
  "step_rewards": [
562
  19.26,
563
  17.0,
 
704
  "raw_reward": 62.465,
705
  "score": 0.05,
706
  "baseline_reward": 62.465,
707
+ "heuristic_reward": 86.065,
708
+ "target_reward": 96.065,
709
  "step_rewards": [
710
  33.2,
711
  -7.8,
 
746
  "raw_reward": 780.6,
747
  "score": 0.05,
748
  "baseline_reward": 780.6,
749
+ "heuristic_reward": 945.868,
750
+ "target_reward": 955.868,
751
  "step_rewards": [
752
  31.055,
753
  70.415,
 
788
  "raw_reward": -29.105,
789
  "score": 0.05,
790
  "baseline_reward": -29.105,
791
+ "heuristic_reward": 142.784,
792
+ "target_reward": 152.784,
793
  "step_rewards": [
794
  49.165,
795
  10.275,
 
830
  "raw_reward": 126.78,
831
  "score": 0.05,
832
  "baseline_reward": 126.78,
833
+ "heuristic_reward": 83.171,
834
  "target_reward": 146.78,
835
  "step_rewards": [
836
  0.99,
 
872
  "raw_reward": -1832.7,
873
  "score": 0.05,
874
  "baseline_reward": -1832.7,
875
+ "heuristic_reward": -1275.212,
876
+ "target_reward": -1265.212,
877
  "step_rewards": [
878
  94.155,
879
  -11.865,
 
924
  "raw_reward": -1520.675,
925
  "score": 0.05,
926
  "baseline_reward": -1520.675,
927
+ "heuristic_reward": -1037.244,
928
+ "target_reward": -806.805,
929
  "step_rewards": [
930
  89.685,
931
  23.305,
 
976
  "raw_reward": -616.805,
977
  "score": 0.05,
978
  "baseline_reward": -616.805,
979
+ "heuristic_reward": -587.46,
980
+ "target_reward": -385.957,
981
  "step_rewards": [
982
  21.58,
983
  50.63,
 
1028
  "raw_reward": -878.21,
1029
  "score": 0.05,
1030
  "baseline_reward": -878.21,
1031
+ "heuristic_reward": -551.885,
1032
+ "target_reward": -541.885,
1033
  "step_rewards": [
1034
  66.25,
1035
  24.645,
 
1079
  "task_id": "cooperative_restock",
1080
  "internal_task_id": "v1_cooperative_restock",
1081
  "seed": 401,
1082
+ "raw_reward": 267.48,
1083
+ "score": 0.9034,
1084
  "baseline_reward": 179.02,
1085
+ "heuristic_reward": 267.48,
1086
+ "target_reward": 277.48,
1087
  "step_rewards": [
1088
  19.26,
1089
  17.0,
 
1101
  -25.2,
1102
  4.78,
1103
  -10.33,
1104
+ 2.78,
1105
  27.77,
1106
  1.84,
1107
+ 23.086,
1108
+ -15.954,
1109
+ -3.51,
1110
+ 36.086,
1111
+ -76.144,
1112
+ 13.766
1113
  ]
1114
  },
1115
  {
 
1227
  "task_id": "scarcity_negotiation",
1228
  "internal_task_id": "v1_scarcity_negotiation",
1229
  "seed": 501,
1230
+ "raw_reward": 86.065,
1231
+ "score": 0.7172,
1232
  "baseline_reward": 62.465,
1233
+ "heuristic_reward": 86.065,
1234
+ "target_reward": 96.065,
1235
  "step_rewards": [
1236
  33.2,
1237
  -7.8,
 
1249
  -23.455,
1250
  -29.15,
1251
  -33.145,
1252
+ 17.265,
1253
  -39.085,
1254
+ 30.06,
1255
  71.09,
1256
+ -16.755,
1257
  -56.44,
1258
  61.38,
1259
  -22.72,
1260
+ -43.265,
1261
+ -50.11,
1262
+ -26.76,
1263
+ -66.66,
1264
+ -4.02,
1265
+ -55.44
1266
  ]
1267
  },
1268
  {
1269
  "task_id": "scarcity_negotiation",
1270
  "internal_task_id": "v1_scarcity_negotiation",
1271
  "seed": 503,
1272
+ "raw_reward": 945.868,
1273
+ "score": 0.9457,
1274
  "baseline_reward": 780.6,
1275
+ "heuristic_reward": 945.868,
1276
+ "target_reward": 955.868,
1277
  "step_rewards": [
1278
  31.055,
1279
  70.415,
 
1295
  11.485,
1296
  105.698,
1297
  3.641,
1298
+ 59.08,
1299
  14.69,
1300
  1.29,
1301
  21.501,
1302
+ 71.606,
1303
+ -27.194,
1304
+ 15.786,
1305
+ 17.398,
1306
+ 21.416,
1307
+ -0.987
1308
  ]
1309
  },
1310
  {
1311
  "task_id": "scarcity_negotiation",
1312
  "internal_task_id": "v1_scarcity_negotiation",
1313
  "seed": 505,
1314
+ "raw_reward": 142.784,
1315
+ "score": 0.9477,
1316
  "baseline_reward": -29.105,
1317
+ "heuristic_reward": 142.784,
1318
+ "target_reward": 152.784,
1319
  "step_rewards": [
1320
  49.165,
1321
  10.275,
 
1337
  -3.491,
1338
  29.508,
1339
  -7.837,
1340
+ -18.072,
1341
  70.998,
1342
  19.108,
1343
  -8.292,
1344
  -42.892,
1345
+ 19.268,
1346
  75.658,
1347
+ -21.892,
1348
+ -26.787,
1349
+ 34.868
1350
  ]
1351
  },
1352
  {
1353
  "task_id": "scarcity_negotiation",
1354
  "internal_task_id": "v1_scarcity_negotiation",
1355
  "seed": 507,
1356
+ "raw_reward": 83.171,
1357
  "score": 0.0001,
1358
  "baseline_reward": 126.78,
1359
+ "heuristic_reward": 83.171,
1360
  "target_reward": 146.78,
1361
  "step_rewards": [
1362
  0.99,
 
1379
  -14.11,
1380
  21.965,
1381
  -46.635,
1382
+ -4.205,
1383
  36.235,
1384
+ 13.895,
1385
  -35.985,
1386
+ -46.525,
1387
  -63.69,
1388
  -13.795,
1389
  53.758,
1390
+ -47.697,
1391
+ -5.132
1392
  ]
1393
  },
1394
  {
1395
  "task_id": "crisis_coalition",
1396
  "internal_task_id": "v1_crisis_coalition",
1397
  "seed": 601,
1398
+ "raw_reward": -1275.212,
1399
+ "score": 0.9832,
1400
  "baseline_reward": -1832.7,
1401
+ "heuristic_reward": -1275.212,
1402
+ "target_reward": -1265.212,
1403
  "step_rewards": [
1404
  94.155,
1405
  -11.865,
 
1410
  -11.296,
1411
  5.93,
1412
  34.015,
1413
+ -50.975,
1414
  -70.91,
1415
+ -41.885,
1416
  -32.325,
1417
  -80.325,
1418
  -23.46,
1419
  -67.055,
1420
  -21.26,
1421
  -25.57,
1422
+ -70.335,
1423
+ 17.26,
1424
+ -13.375,
1425
+ -50.795,
1426
+ 41.235,
1427
+ -74.16,
1428
+ -173.33,
1429
+ -9.17,
1430
+ -67.36,
1431
+ -95.2,
1432
+ -113.73,
1433
+ -72.26,
1434
+ 15.655,
1435
+ -60.27,
1436
+ -61.275,
1437
+ -54.905,
1438
+ -36.335,
1439
+ 2.585,
1440
+ -42.35,
1441
+ -67.77,
1442
+ -91.87,
1443
+ -59.56
1444
  ]
1445
  },
1446
  {
1447
  "task_id": "crisis_coalition",
1448
  "internal_task_id": "v1_crisis_coalition",
1449
  "seed": 603,
1450
+ "raw_reward": -1037.244,
1451
+ "score": 0.6933,
1452
  "baseline_reward": -1520.675,
1453
+ "heuristic_reward": -1037.244,
1454
+ "target_reward": -806.805,
1455
  "step_rewards": [
1456
  89.685,
1457
  23.305,
 
1461
  -16.79,
1462
  -19.78,
1463
  -82.715,
1464
+ -89.915,
1465
  -51.305,
1466
  -24.705,
1467
  -15.38,
1468
+ -113.865,
1469
+ -42.72,
1470
+ -32.49,
1471
+ 23.71,
1472
+ -82.405,
1473
+ 5.46,
1474
+ -7.545,
1475
+ -47.02,
1476
+ -46.535,
1477
+ -10.49,
1478
+ 27.45,
1479
+ -5.065,
1480
+ -66.04,
1481
+ 39.375,
1482
+ -53.295,
1483
+ 49.015,
1484
+ -57.75,
1485
+ 42.705,
1486
+ -37.03,
1487
+ -22.43,
1488
+ -37.265,
1489
+ -14.035,
1490
+ -46.332,
1491
+ -71.617,
1492
+ -59.102,
1493
+ -109.307,
1494
+ 48.983,
1495
+ -95.637
1496
  ]
1497
  },
1498
  {
1499
  "task_id": "crisis_coalition",
1500
  "internal_task_id": "v1_crisis_coalition",
1501
  "seed": 605,
1502
+ "raw_reward": -587.46,
1503
+ "score": 0.1707,
1504
  "baseline_reward": -616.805,
1505
+ "heuristic_reward": -587.46,
1506
+ "target_reward": -385.957,
1507
  "step_rewards": [
1508
  21.58,
1509
  50.63,
 
1522
  74.566,
1523
  26.691,
1524
  -13.224,
1525
+ 7.156,
1526
  18.76,
1527
  -59.39,
1528
+ 24.24,
1529
  72.685,
1530
+ -11.85,
1531
+ -49.585,
1532
+ 22.24,
1533
+ -4.315,
1534
+ -68.28,
1535
+ -20.945,
1536
+ -39.03,
1537
+ -93.41,
1538
+ -27.63,
1539
+ -42.205,
1540
+ -87.32,
1541
+ -152.37,
1542
+ -46.565,
1543
+ -16.765,
1544
+ -188.075,
1545
+ -89.805,
1546
+ -55.555,
1547
+ -35.085
1548
  ]
1549
  },
1550
  {
1551
  "task_id": "crisis_coalition",
1552
  "internal_task_id": "v1_crisis_coalition",
1553
  "seed": 607,
1554
+ "raw_reward": -551.885,
1555
+ "score": 0.9717,
1556
  "baseline_reward": -878.21,
1557
+ "heuristic_reward": -551.885,
1558
+ "target_reward": -541.885,
1559
  "step_rewards": [
1560
  66.25,
1561
  24.645,
 
1565
  12.64,
1566
  72.245,
1567
  -6.89,
1568
+ 0.995,
1569
  40.235,
1570
  -32.635,
1571
  57.026,
1572
+ -26.244,
1573
+ 2.521,
1574
+ 33.181,
1575
+ -45.764,
1576
+ -47.589,
1577
+ -10.564,
1578
+ -65.614,
1579
+ -86.679,
1580
+ 41.441,
1581
+ -67.609,
1582
+ -63.249,
1583
+ -15.98,
1584
+ -34.024,
1585
+ -62.459,
1586
+ -39.5,
1587
+ -28.444,
1588
+ -74.94,
1589
+ -72.715,
1590
+ 90.741,
1591
+ -75.724,
1592
+ 10.976,
1593
+ -0.029,
1594
+ -64.579,
1595
+ -76.064,
1596
+ -62.649,
1597
+ 104.051,
1598
+ -75.754,
1599
+ -23.839
1600
  ]
1601
  }
1602
  ],
 
1605
  "task_id": "cooperative_restock",
1606
  "internal_task_id": "v1_cooperative_restock",
1607
  "seed": 401,
1608
+ "raw_reward": 267.4800000000001,
1609
  "score": 0.9999,
1610
  "baseline_reward": 179.02,
1611
+ "heuristic_reward": 267.48,
1612
+ "target_reward": 267.4800000000001,
1613
  "step_rewards": []
1614
  },
1615
  {
 
1649
  "task_id": "scarcity_negotiation",
1650
  "internal_task_id": "v1_scarcity_negotiation",
1651
  "seed": 501,
1652
+ "raw_reward": 86.06499999999991,
1653
  "score": 0.9999,
1654
  "baseline_reward": 62.465,
1655
+ "heuristic_reward": 86.065,
1656
+ "target_reward": 86.06499999999991,
1657
  "step_rewards": []
1658
  },
1659
  {
1660
  "task_id": "scarcity_negotiation",
1661
  "internal_task_id": "v1_scarcity_negotiation",
1662
  "seed": 503,
1663
+ "raw_reward": 945.8678,
1664
  "score": 0.9999,
1665
  "baseline_reward": 780.6,
1666
+ "heuristic_reward": 945.868,
1667
+ "target_reward": 945.8678,
1668
  "step_rewards": []
1669
  },
1670
  {
1671
  "task_id": "scarcity_negotiation",
1672
  "internal_task_id": "v1_scarcity_negotiation",
1673
  "seed": 505,
1674
+ "raw_reward": 142.78359999999998,
1675
  "score": 0.9999,
1676
  "baseline_reward": -29.105,
1677
+ "heuristic_reward": 142.784,
1678
+ "target_reward": 142.78359999999998,
1679
  "step_rewards": []
1680
  },
1681
  {
 
1685
  "raw_reward": 135.1099999999999,
1686
  "score": 0.9999,
1687
  "baseline_reward": 126.78,
1688
+ "heuristic_reward": 83.171,
1689
  "target_reward": 135.1099999999999,
1690
  "step_rewards": []
1691
  },
 
1693
  "task_id": "crisis_coalition",
1694
  "internal_task_id": "v1_crisis_coalition",
1695
  "seed": 601,
1696
+ "raw_reward": -1275.212,
1697
  "score": 0.9999,
1698
  "baseline_reward": -1832.7,
1699
+ "heuristic_reward": -1275.212,
1700
+ "target_reward": -1275.212,
1701
  "step_rewards": []
1702
  },
1703
  {
1704
  "task_id": "crisis_coalition",
1705
  "internal_task_id": "v1_crisis_coalition",
1706
  "seed": 603,
1707
+ "raw_reward": -806.8049999999996,
1708
  "score": 0.9999,
1709
  "baseline_reward": -1520.675,
1710
+ "heuristic_reward": -1037.244,
1711
+ "target_reward": -806.8049999999996,
1712
  "step_rewards": []
1713
  },
1714
  {
1715
  "task_id": "crisis_coalition",
1716
  "internal_task_id": "v1_crisis_coalition",
1717
  "seed": 605,
1718
+ "raw_reward": -385.95699999999977,
1719
  "score": 0.9999,
1720
  "baseline_reward": -616.805,
1721
+ "heuristic_reward": -587.46,
1722
+ "target_reward": -385.95699999999977,
1723
  "step_rewards": []
1724
  },
1725
  {
1726
  "task_id": "crisis_coalition",
1727
  "internal_task_id": "v1_crisis_coalition",
1728
  "seed": 607,
1729
+ "raw_reward": -551.8849999999998,
1730
  "score": 0.9999,
1731
  "baseline_reward": -878.21,
1732
+ "heuristic_reward": -551.885,
1733
+ "target_reward": -551.8849999999998,
1734
  "step_rewards": []
1735
  }
1736
  ]
results/subagent_episode.json ADDED
@@ -0,0 +1,1952 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "task": "crisis_coalition",
3
+ "seed": 12345,
4
+ "system_prompt": "You are a small central-planning subagent playing SupplyMind.\nYou do not see raw customer orders. You only see warehouse reports, depot stock, route costs, market signals, and reward feedback.\n\nGoal:\nMaximize global network welfare over the full episode, not just this round.\n\nAction JSON schema:\n{\n \"central_procurements\": [{\"sku\": \"fresh_milk\", \"units\": 2}],\n \"central_replenishments\": [{\"to_warehouse\": \"north\", \"sku\": \"insulin_pack\", \"units\": 2}],\n \"offer_matches\": [{\"offer_signal_id\": \"west:offer:fresh_milk\", \"request_signal_id\": \"north:request:fresh_milk\", \"units\": 2, \"compensation\": 12.0}],\n \"inventory_transfers\": [{\"from_warehouse\": \"west\", \"to_warehouse\": \"north\", \"sku\": \"fresh_milk\", \"units\": 2, \"compensation\": 12.0}],\n \"priority_policy\": [],\n \"defer_orders\": [],\n \"coalition_deals\": []\n}\n\nPolicy:\n1. Ship depot stock to urgent warehouses when trucks and depot inventory are available.\n2. Buy into central depot when repeated forecast pressure is high and depot stock is low; purchases arrive after lead time.\n3. Prefer offer_matches over direct transfers when public offers and requests already exist.\n4. Do not overbuy late in the episode.\n5. Avoid transfers that look unlikely to satisfy the source warehouse's local incentive.\nReturn JSON only.",
5
+ "episode_summary": {
6
+ "raw_reward": -918.535,
7
+ "baseline_reward": -1417.9,
8
+ "target_reward": -908.535,
9
+ "heuristic_reward": -918.535,
10
+ "graded_score": 0.9813
11
+ },
12
+ "timeline": [
13
+ {
14
+ "round": 0,
15
+ "action": {
16
+ "fulfillments": [],
17
+ "central_procurements": [],
18
+ "central_replenishments": [
19
+ {
20
+ "to_warehouse": "east",
21
+ "sku": "usb_c_charger",
22
+ "units": 1
23
+ },
24
+ {
25
+ "to_warehouse": "central",
26
+ "sku": "fresh_milk",
27
+ "units": 2
28
+ }
29
+ ],
30
+ "inventory_transfers": [],
31
+ "driver_loans": [],
32
+ "offer_matches": [],
33
+ "priority_policy": [],
34
+ "defer_orders": [],
35
+ "coalition_deals": []
36
+ },
37
+ "reward": {
38
+ "step_reward": 21.57,
39
+ "cumulative_reward": 21.57,
40
+ "components": {
41
+ "central_replenishment_cost": -6.6,
42
+ "central_replenishment_bonus": 0.75,
43
+ "fulfilled_order_value": 44.0,
44
+ "delivery_cost": -2.0,
45
+ "holding_cost": -9.36,
46
+ "waste_penalty": -2.7,
47
+ "fairness_penalty": -2.52
48
+ }
49
+ },
50
+ "events": [
51
+ "central depot sent 1 usb_c_charger to east",
52
+ "central depot sent 2 fresh_milk to central",
53
+ "north local agent fulfilled 2 insulin_pack"
54
+ ],
55
+ "components": {
56
+ "central_replenishment_cost": -6.6,
57
+ "central_replenishment_bonus": 0.75,
58
+ "fulfilled_order_value": 44.0,
59
+ "delivery_cost": -2.0,
60
+ "holding_cost": -9.36,
61
+ "waste_penalty": -2.7,
62
+ "fairness_penalty": -2.52
63
+ },
64
+ "done": false
65
+ },
66
+ {
67
+ "round": 1,
68
+ "action": {
69
+ "fulfillments": [],
70
+ "central_procurements": [],
71
+ "central_replenishments": [],
72
+ "inventory_transfers": [],
73
+ "driver_loans": [],
74
+ "offer_matches": [],
75
+ "priority_policy": [],
76
+ "defer_orders": [],
77
+ "coalition_deals": []
78
+ },
79
+ "reward": {
80
+ "step_reward": 107.77,
81
+ "cumulative_reward": 129.34,
82
+ "components": {
83
+ "fulfilled_order_value": 149.0,
84
+ "delivery_cost": -8.0,
85
+ "holding_cost": -8.84,
86
+ "waste_penalty": -1.35,
87
+ "fairness_penalty": -23.04
88
+ }
89
+ },
90
+ "events": [
91
+ "east local agent fulfilled 3 fresh_milk",
92
+ "east local agent fulfilled 3 insulin_pack",
93
+ "south local agent fulfilled 1 insulin_pack",
94
+ "central local agent fulfilled 1 insulin_pack"
95
+ ],
96
+ "components": {
97
+ "fulfilled_order_value": 149.0,
98
+ "delivery_cost": -8.0,
99
+ "holding_cost": -8.84,
100
+ "waste_penalty": -1.35,
101
+ "fairness_penalty": -23.04
102
+ },
103
+ "done": false
104
+ },
105
+ {
106
+ "round": 2,
107
+ "action": {
108
+ "fulfillments": [],
109
+ "central_procurements": [],
110
+ "central_replenishments": [
111
+ {
112
+ "to_warehouse": "south",
113
+ "sku": "fresh_milk",
114
+ "units": 2
115
+ }
116
+ ],
117
+ "inventory_transfers": [],
118
+ "driver_loans": [],
119
+ "offer_matches": [],
120
+ "priority_policy": [],
121
+ "defer_orders": [],
122
+ "coalition_deals": []
123
+ },
124
+ "reward": {
125
+ "step_reward": 6.68,
126
+ "cumulative_reward": 136.02,
127
+ "components": {
128
+ "central_replenishment_cost": -4.4,
129
+ "central_replenishment_bonus": 0.5,
130
+ "fulfilled_order_value": 52.0,
131
+ "delivery_cost": -4.0,
132
+ "holding_cost": -8.71,
133
+ "waste_penalty": -1.35,
134
+ "fairness_penalty": -27.36
135
+ }
136
+ },
137
+ "events": [
138
+ "central depot sent 2 fresh_milk to south",
139
+ "east local agent fulfilled 1 fresh_milk",
140
+ "south local agent fulfilled 3 fresh_milk"
141
+ ],
142
+ "components": {
143
+ "central_replenishment_cost": -4.4,
144
+ "central_replenishment_bonus": 0.5,
145
+ "fulfilled_order_value": 52.0,
146
+ "delivery_cost": -4.0,
147
+ "holding_cost": -8.71,
148
+ "waste_penalty": -1.35,
149
+ "fairness_penalty": -27.36
150
+ },
151
+ "done": false
152
+ },
153
+ {
154
+ "round": 3,
155
+ "action": {
156
+ "fulfillments": [],
157
+ "central_procurements": [],
158
+ "central_replenishments": [
159
+ {
160
+ "to_warehouse": "south",
161
+ "sku": "fresh_milk",
162
+ "units": 1
163
+ }
164
+ ],
165
+ "inventory_transfers": [],
166
+ "driver_loans": [],
167
+ "offer_matches": [],
168
+ "priority_policy": [],
169
+ "defer_orders": [],
170
+ "coalition_deals": []
171
+ },
172
+ "reward": {
173
+ "step_reward": -16.2,
174
+ "cumulative_reward": 119.82,
175
+ "components": {
176
+ "central_replenishment_cost": -2.2,
177
+ "central_replenishment_bonus": 0.25,
178
+ "fulfilled_order_value": 39.0,
179
+ "delivery_cost": -3.0,
180
+ "holding_cost": -8.58,
181
+ "waste_penalty": -1.35,
182
+ "fairness_penalty": -40.32
183
+ }
184
+ },
185
+ "events": [
186
+ "central depot sent 1 fresh_milk to south",
187
+ "east local agent fulfilled 3 fresh_milk"
188
+ ],
189
+ "components": {
190
+ "central_replenishment_cost": -2.2,
191
+ "central_replenishment_bonus": 0.25,
192
+ "fulfilled_order_value": 39.0,
193
+ "delivery_cost": -3.0,
194
+ "holding_cost": -8.58,
195
+ "waste_penalty": -1.35,
196
+ "fairness_penalty": -40.32
197
+ },
198
+ "done": false
199
+ },
200
+ {
201
+ "round": 4,
202
+ "action": {
203
+ "fulfillments": [],
204
+ "central_procurements": [],
205
+ "central_replenishments": [],
206
+ "inventory_transfers": [],
207
+ "driver_loans": [],
208
+ "offer_matches": [],
209
+ "priority_policy": [],
210
+ "defer_orders": [],
211
+ "coalition_deals": []
212
+ },
213
+ "reward": {
214
+ "step_reward": -6.725,
215
+ "cumulative_reward": 113.095,
216
+ "components": {
217
+ "fulfilled_order_value": 59.0,
218
+ "delivery_cost": -5.0,
219
+ "holding_cost": -8.255,
220
+ "waste_penalty": -1.35,
221
+ "fairness_penalty": -51.12
222
+ }
223
+ },
224
+ "events": [
225
+ "east local agent fulfilled 3 rice_bag_5kg",
226
+ "campus local agent fulfilled 2 fresh_milk"
227
+ ],
228
+ "components": {
229
+ "fulfilled_order_value": 59.0,
230
+ "delivery_cost": -5.0,
231
+ "holding_cost": -8.255,
232
+ "waste_penalty": -1.35,
233
+ "fairness_penalty": -51.12
234
+ },
235
+ "done": false
236
+ },
237
+ {
238
+ "round": 5,
239
+ "action": {
240
+ "fulfillments": [],
241
+ "central_procurements": [],
242
+ "central_replenishments": [
243
+ {
244
+ "to_warehouse": "campus",
245
+ "sku": "insulin_pack",
246
+ "units": 2
247
+ }
248
+ ],
249
+ "inventory_transfers": [],
250
+ "driver_loans": [],
251
+ "offer_matches": [],
252
+ "priority_policy": [],
253
+ "defer_orders": [],
254
+ "coalition_deals": []
255
+ },
256
+ "reward": {
257
+ "step_reward": 102.83,
258
+ "cumulative_reward": 215.925,
259
+ "components": {
260
+ "central_replenishment_cost": -4.4,
261
+ "central_replenishment_bonus": 0.5,
262
+ "fulfilled_order_value": 176.0,
263
+ "delivery_cost": -9.0,
264
+ "holding_cost": -7.8,
265
+ "waste_penalty": -1.35,
266
+ "fairness_penalty": -51.12
267
+ }
268
+ },
269
+ "events": [
270
+ "central depot sent 2 insulin_pack to campus",
271
+ "south local agent fulfilled 2 rice_bag_5kg",
272
+ "west local agent fulfilled 3 insulin_pack",
273
+ "campus local agent fulfilled 4 insulin_pack"
274
+ ],
275
+ "components": {
276
+ "central_replenishment_cost": -4.4,
277
+ "central_replenishment_bonus": 0.5,
278
+ "fulfilled_order_value": 176.0,
279
+ "delivery_cost": -9.0,
280
+ "holding_cost": -7.8,
281
+ "waste_penalty": -1.35,
282
+ "fairness_penalty": -51.12
283
+ },
284
+ "done": false
285
+ },
286
+ {
287
+ "round": 6,
288
+ "action": {
289
+ "fulfillments": [],
290
+ "central_procurements": [],
291
+ "central_replenishments": [
292
+ {
293
+ "to_warehouse": "east",
294
+ "sku": "rice_bag_5kg",
295
+ "units": 1
296
+ }
297
+ ],
298
+ "inventory_transfers": [],
299
+ "driver_loans": [],
300
+ "offer_matches": [],
301
+ "priority_policy": [],
302
+ "defer_orders": [],
303
+ "coalition_deals": []
304
+ },
305
+ "reward": {
306
+ "step_reward": -25.625,
307
+ "cumulative_reward": 190.3,
308
+ "components": {
309
+ "central_replenishment_cost": -2.2,
310
+ "central_replenishment_bonus": 0.25,
311
+ "fulfilled_order_value": 44.0,
312
+ "delivery_cost": -4.0,
313
+ "holding_cost": -7.605,
314
+ "waste_penalty": -1.35,
315
+ "fairness_penalty": -54.72
316
+ }
317
+ },
318
+ "events": [
319
+ "central depot sent 1 rice_bag_5kg to east",
320
+ "north local agent fulfilled 3 rice_bag_5kg",
321
+ "east local agent fulfilled 1 rice_bag_5kg"
322
+ ],
323
+ "components": {
324
+ "central_replenishment_cost": -2.2,
325
+ "central_replenishment_bonus": 0.25,
326
+ "fulfilled_order_value": 44.0,
327
+ "delivery_cost": -4.0,
328
+ "holding_cost": -7.605,
329
+ "waste_penalty": -1.35,
330
+ "fairness_penalty": -54.72
331
+ },
332
+ "done": false
333
+ },
334
+ {
335
+ "round": 7,
336
+ "action": {
337
+ "fulfillments": [],
338
+ "central_procurements": [],
339
+ "central_replenishments": [
340
+ {
341
+ "to_warehouse": "central",
342
+ "sku": "insulin_pack",
343
+ "units": 1
344
+ }
345
+ ],
346
+ "inventory_transfers": [],
347
+ "driver_loans": [],
348
+ "offer_matches": [],
349
+ "priority_policy": [],
350
+ "defer_orders": [],
351
+ "coalition_deals": []
352
+ },
353
+ "reward": {
354
+ "step_reward": 20.57,
355
+ "cumulative_reward": 210.87,
356
+ "components": {
357
+ "central_replenishment_cost": -2.2,
358
+ "central_replenishment_bonus": 0.25,
359
+ "fulfilled_order_value": 90.0,
360
+ "delivery_cost": -4.0,
361
+ "holding_cost": -7.41,
362
+ "waste_penalty": -1.35,
363
+ "fairness_penalty": -54.72
364
+ }
365
+ },
366
+ "events": [
367
+ "central depot sent 1 insulin_pack to central",
368
+ "central local agent fulfilled 3 insulin_pack",
369
+ "campus local agent fulfilled 1 usb_c_charger"
370
+ ],
371
+ "components": {
372
+ "central_replenishment_cost": -2.2,
373
+ "central_replenishment_bonus": 0.25,
374
+ "fulfilled_order_value": 90.0,
375
+ "delivery_cost": -4.0,
376
+ "holding_cost": -7.41,
377
+ "waste_penalty": -1.35,
378
+ "fairness_penalty": -54.72
379
+ },
380
+ "done": false
381
+ },
382
+ {
383
+ "round": 8,
384
+ "action": {
385
+ "fulfillments": [],
386
+ "central_procurements": [],
387
+ "central_replenishments": [
388
+ {
389
+ "to_warehouse": "west",
390
+ "sku": "rice_bag_5kg",
391
+ "units": 2
392
+ }
393
+ ],
394
+ "inventory_transfers": [],
395
+ "driver_loans": [],
396
+ "offer_matches": [],
397
+ "priority_policy": [],
398
+ "defer_orders": [],
399
+ "coalition_deals": []
400
+ },
401
+ "reward": {
402
+ "step_reward": -27.25,
403
+ "cumulative_reward": 183.62,
404
+ "components": {
405
+ "central_replenishment_cost": -4.4,
406
+ "central_replenishment_bonus": 0.5,
407
+ "fulfilled_order_value": 44.0,
408
+ "delivery_cost": -4.0,
409
+ "holding_cost": -7.28,
410
+ "waste_penalty": -1.35,
411
+ "fairness_penalty": -54.72
412
+ }
413
+ },
414
+ "events": [
415
+ "central depot sent 2 rice_bag_5kg to west",
416
+ "west local agent fulfilled 4 rice_bag_5kg"
417
+ ],
418
+ "components": {
419
+ "central_replenishment_cost": -4.4,
420
+ "central_replenishment_bonus": 0.5,
421
+ "fulfilled_order_value": 44.0,
422
+ "delivery_cost": -4.0,
423
+ "holding_cost": -7.28,
424
+ "waste_penalty": -1.35,
425
+ "fairness_penalty": -54.72
426
+ },
427
+ "done": false
428
+ },
429
+ {
430
+ "round": 9,
431
+ "action": {
432
+ "fulfillments": [],
433
+ "central_procurements": [],
434
+ "central_replenishments": [
435
+ {
436
+ "to_warehouse": "east",
437
+ "sku": "fresh_milk",
438
+ "units": 1
439
+ }
440
+ ],
441
+ "inventory_transfers": [],
442
+ "driver_loans": [],
443
+ "offer_matches": [],
444
+ "priority_policy": [],
445
+ "defer_orders": [],
446
+ "coalition_deals": []
447
+ },
448
+ "reward": {
449
+ "step_reward": -35.09,
450
+ "cumulative_reward": 148.53,
451
+ "components": {
452
+ "central_replenishment_cost": -2.2,
453
+ "central_replenishment_bonus": 0.25,
454
+ "fulfilled_order_value": 50.0,
455
+ "delivery_cost": -3.0,
456
+ "holding_cost": -7.15,
457
+ "waste_penalty": -1.35,
458
+ "fairness_penalty": -71.64
459
+ }
460
+ },
461
+ "events": [
462
+ "central depot sent 1 fresh_milk to east",
463
+ "east local agent fulfilled 1 usb_c_charger",
464
+ "east local agent fulfilled 2 fresh_milk"
465
+ ],
466
+ "components": {
467
+ "central_replenishment_cost": -2.2,
468
+ "central_replenishment_bonus": 0.25,
469
+ "fulfilled_order_value": 50.0,
470
+ "delivery_cost": -3.0,
471
+ "holding_cost": -7.15,
472
+ "waste_penalty": -1.35,
473
+ "fairness_penalty": -71.64
474
+ },
475
+ "done": false
476
+ },
477
+ {
478
+ "round": 10,
479
+ "action": {
480
+ "fulfillments": [],
481
+ "central_procurements": [],
482
+ "central_replenishments": [
483
+ {
484
+ "to_warehouse": "north",
485
+ "sku": "usb_c_charger",
486
+ "units": 1
487
+ }
488
+ ],
489
+ "inventory_transfers": [],
490
+ "driver_loans": [],
491
+ "offer_matches": [],
492
+ "priority_policy": [],
493
+ "defer_orders": [],
494
+ "coalition_deals": []
495
+ },
496
+ "reward": {
497
+ "step_reward": -8.695,
498
+ "cumulative_reward": 139.835,
499
+ "components": {
500
+ "central_replenishment_cost": -2.2,
501
+ "central_replenishment_bonus": 0.25,
502
+ "fulfilled_order_value": 70.0,
503
+ "delivery_cost": -4.0,
504
+ "holding_cost": -6.955,
505
+ "waste_penalty": -1.35,
506
+ "fairness_penalty": -64.44
507
+ }
508
+ },
509
+ "events": [
510
+ "central depot sent 1 usb_c_charger to north",
511
+ "north local agent fulfilled 2 usb_c_charger",
512
+ "riverside local agent fulfilled 2 rice_bag_5kg"
513
+ ],
514
+ "components": {
515
+ "central_replenishment_cost": -2.2,
516
+ "central_replenishment_bonus": 0.25,
517
+ "fulfilled_order_value": 70.0,
518
+ "delivery_cost": -4.0,
519
+ "holding_cost": -6.955,
520
+ "waste_penalty": -1.35,
521
+ "fairness_penalty": -64.44
522
+ },
523
+ "done": false
524
+ },
525
+ {
526
+ "round": 11,
527
+ "action": {
528
+ "fulfillments": [],
529
+ "central_procurements": [],
530
+ "central_replenishments": [
531
+ {
532
+ "to_warehouse": "east",
533
+ "sku": "fresh_milk",
534
+ "units": 2
535
+ }
536
+ ],
537
+ "inventory_transfers": [],
538
+ "driver_loans": [],
539
+ "offer_matches": [],
540
+ "priority_policy": [],
541
+ "defer_orders": [],
542
+ "coalition_deals": []
543
+ },
544
+ "reward": {
545
+ "step_reward": -22.9,
546
+ "cumulative_reward": 116.935,
547
+ "components": {
548
+ "central_replenishment_cost": -4.4,
549
+ "central_replenishment_bonus": 0.5,
550
+ "fulfilled_order_value": 61.0,
551
+ "delivery_cost": -3.0,
552
+ "holding_cost": -6.89,
553
+ "waste_penalty": -1.35,
554
+ "fairness_penalty": -68.76
555
+ }
556
+ },
557
+ "events": [
558
+ "central depot sent 2 fresh_milk to east",
559
+ "east local agent fulfilled 1 fresh_milk",
560
+ "south local agent fulfilled 2 usb_c_charger"
561
+ ],
562
+ "components": {
563
+ "central_replenishment_cost": -4.4,
564
+ "central_replenishment_bonus": 0.5,
565
+ "fulfilled_order_value": 61.0,
566
+ "delivery_cost": -3.0,
567
+ "holding_cost": -6.89,
568
+ "waste_penalty": -1.35,
569
+ "fairness_penalty": -68.76
570
+ },
571
+ "done": false
572
+ },
573
+ {
574
+ "round": 12,
575
+ "action": {
576
+ "fulfillments": [],
577
+ "central_procurements": [
578
+ {
579
+ "sku": "fresh_milk",
580
+ "units": 2
581
+ }
582
+ ],
583
+ "central_replenishments": [
584
+ {
585
+ "to_warehouse": "east",
586
+ "sku": "fresh_milk",
587
+ "units": 2
588
+ }
589
+ ],
590
+ "inventory_transfers": [],
591
+ "driver_loans": [],
592
+ "offer_matches": [
593
+ {
594
+ "offer_signal_id": "west:offer:fresh_milk",
595
+ "request_signal_id": "south:request:fresh_milk",
596
+ "units": 3,
597
+ "compensation": 15.18
598
+ }
599
+ ],
600
+ "priority_policy": [],
601
+ "defer_orders": [],
602
+ "coalition_deals": []
603
+ },
604
+ "reward": {
605
+ "step_reward": -15.52,
606
+ "cumulative_reward": 101.415,
607
+ "components": {
608
+ "central_procurement_cost": -8.0,
609
+ "central_replenishment_cost": -4.4,
610
+ "central_replenishment_bonus": 0.5,
611
+ "transfer_cost": -5.175,
612
+ "accepted_trade_bonus": 0.4,
613
+ "fulfilled_order_value": 100.0,
614
+ "delivery_cost": -7.0,
615
+ "holding_cost": -6.565,
616
+ "fairness_penalty": -89.28,
617
+ "coalition_bonus": 4.0
618
+ }
619
+ },
620
+ "events": [
621
+ "central bought 2 fresh_milk for depot arrival at round 15",
622
+ "central depot sent 2 fresh_milk to east",
623
+ "central approved 3 fresh_milk from west to south via transfer truck capacity",
624
+ "west transferred 3 fresh_milk to south",
625
+ "east local agent fulfilled 3 fresh_milk",
626
+ "east local agent fulfilled 1 insulin_pack",
627
+ "south local agent fulfilled 3 fresh_milk"
628
+ ],
629
+ "components": {
630
+ "central_procurement_cost": -8.0,
631
+ "central_replenishment_cost": -4.4,
632
+ "central_replenishment_bonus": 0.5,
633
+ "transfer_cost": -5.175,
634
+ "accepted_trade_bonus": 0.4,
635
+ "fulfilled_order_value": 100.0,
636
+ "delivery_cost": -7.0,
637
+ "holding_cost": -6.565,
638
+ "fairness_penalty": -89.28,
639
+ "coalition_bonus": 4.0
640
+ },
641
+ "done": false
642
+ },
643
+ {
644
+ "round": 13,
645
+ "action": {
646
+ "fulfillments": [],
647
+ "central_procurements": [],
648
+ "central_replenishments": [
649
+ {
650
+ "to_warehouse": "north",
651
+ "sku": "fresh_milk",
652
+ "units": 1
653
+ }
654
+ ],
655
+ "inventory_transfers": [],
656
+ "driver_loans": [],
657
+ "offer_matches": [],
658
+ "priority_policy": [],
659
+ "defer_orders": [],
660
+ "coalition_deals": []
661
+ },
662
+ "reward": {
663
+ "step_reward": 25.78,
664
+ "cumulative_reward": 127.195,
665
+ "components": {
666
+ "central_replenishment_cost": -2.2,
667
+ "central_replenishment_bonus": 0.25,
668
+ "fulfilled_order_value": 116.0,
669
+ "delivery_cost": -8.0,
670
+ "holding_cost": -6.11,
671
+ "fairness_penalty": -74.16
672
+ }
673
+ },
674
+ "events": [
675
+ "central depot sent 1 fresh_milk to north",
676
+ "north local agent fulfilled 3 fresh_milk",
677
+ "riverside local agent fulfilled 2 insulin_pack",
678
+ "campus local agent fulfilled 3 rice_bag_5kg"
679
+ ],
680
+ "components": {
681
+ "central_replenishment_cost": -2.2,
682
+ "central_replenishment_bonus": 0.25,
683
+ "fulfilled_order_value": 116.0,
684
+ "delivery_cost": -8.0,
685
+ "holding_cost": -6.11,
686
+ "fairness_penalty": -74.16
687
+ },
688
+ "done": false
689
+ },
690
+ {
691
+ "round": 14,
692
+ "action": {
693
+ "fulfillments": [],
694
+ "central_procurements": [],
695
+ "central_replenishments": [
696
+ {
697
+ "to_warehouse": "south",
698
+ "sku": "insulin_pack",
699
+ "units": 1
700
+ }
701
+ ],
702
+ "inventory_transfers": [],
703
+ "driver_loans": [],
704
+ "offer_matches": [],
705
+ "priority_policy": [],
706
+ "defer_orders": [],
707
+ "coalition_deals": []
708
+ },
709
+ "reward": {
710
+ "step_reward": -19.09,
711
+ "cumulative_reward": 108.105,
712
+ "components": {
713
+ "central_replenishment_cost": -2.2,
714
+ "central_replenishment_bonus": 0.25,
715
+ "fulfilled_order_value": 66.0,
716
+ "delivery_cost": -3.0,
717
+ "holding_cost": -5.98,
718
+ "fairness_penalty": -74.16
719
+ }
720
+ },
721
+ "events": [
722
+ "central depot sent 1 insulin_pack to south",
723
+ "south local agent fulfilled 3 insulin_pack"
724
+ ],
725
+ "components": {
726
+ "central_replenishment_cost": -2.2,
727
+ "central_replenishment_bonus": 0.25,
728
+ "fulfilled_order_value": 66.0,
729
+ "delivery_cost": -3.0,
730
+ "holding_cost": -5.98,
731
+ "fairness_penalty": -74.16
732
+ },
733
+ "done": false
734
+ },
735
+ {
736
+ "round": 15,
737
+ "action": {
738
+ "fulfillments": [],
739
+ "central_procurements": [],
740
+ "central_replenishments": [
741
+ {
742
+ "to_warehouse": "east",
743
+ "sku": "insulin_pack",
744
+ "units": 1
745
+ }
746
+ ],
747
+ "inventory_transfers": [],
748
+ "driver_loans": [],
749
+ "offer_matches": [],
750
+ "priority_policy": [],
751
+ "defer_orders": [],
752
+ "coalition_deals": []
753
+ },
754
+ "reward": {
755
+ "step_reward": -27.96,
756
+ "cumulative_reward": 80.145,
757
+ "components": {
758
+ "central_replenishment_cost": -2.2,
759
+ "central_replenishment_bonus": 0.25,
760
+ "fulfilled_order_value": 57.0,
761
+ "delivery_cost": -3.0,
762
+ "holding_cost": -5.85,
763
+ "fairness_penalty": -74.16
764
+ }
765
+ },
766
+ "events": [
767
+ "central depot sent 1 insulin_pack to east",
768
+ "north local agent fulfilled 2 insulin_pack",
769
+ "south local agent fulfilled 1 fresh_milk"
770
+ ],
771
+ "components": {
772
+ "central_replenishment_cost": -2.2,
773
+ "central_replenishment_bonus": 0.25,
774
+ "fulfilled_order_value": 57.0,
775
+ "delivery_cost": -3.0,
776
+ "holding_cost": -5.85,
777
+ "fairness_penalty": -74.16
778
+ },
779
+ "done": false
780
+ },
781
+ {
782
+ "round": 16,
783
+ "action": {
784
+ "fulfillments": [],
785
+ "central_procurements": [],
786
+ "central_replenishments": [
787
+ {
788
+ "to_warehouse": "riverside",
789
+ "sku": "rice_bag_5kg",
790
+ "units": 2
791
+ }
792
+ ],
793
+ "inventory_transfers": [],
794
+ "driver_loans": [],
795
+ "offer_matches": [],
796
+ "priority_policy": [],
797
+ "defer_orders": [],
798
+ "coalition_deals": []
799
+ },
800
+ "reward": {
801
+ "step_reward": -45.925,
802
+ "cumulative_reward": 34.22,
803
+ "components": {
804
+ "central_replenishment_cost": -4.4,
805
+ "central_replenishment_bonus": 0.5,
806
+ "fulfilled_order_value": 33.0,
807
+ "delivery_cost": -3.0,
808
+ "holding_cost": -5.785,
809
+ "fairness_penalty": -66.24
810
+ }
811
+ },
812
+ "events": [
813
+ "central depot sent 2 rice_bag_5kg to riverside",
814
+ "riverside local agent fulfilled 3 rice_bag_5kg"
815
+ ],
816
+ "components": {
817
+ "central_replenishment_cost": -4.4,
818
+ "central_replenishment_bonus": 0.5,
819
+ "fulfilled_order_value": 33.0,
820
+ "delivery_cost": -3.0,
821
+ "holding_cost": -5.785,
822
+ "fairness_penalty": -66.24
823
+ },
824
+ "done": false
825
+ },
826
+ {
827
+ "round": 17,
828
+ "action": {
829
+ "fulfillments": [],
830
+ "central_procurements": [],
831
+ "central_replenishments": [
832
+ {
833
+ "to_warehouse": "riverside",
834
+ "sku": "rice_bag_5kg",
835
+ "units": 2
836
+ }
837
+ ],
838
+ "inventory_transfers": [],
839
+ "driver_loans": [],
840
+ "offer_matches": [],
841
+ "priority_policy": [],
842
+ "defer_orders": [],
843
+ "coalition_deals": []
844
+ },
845
+ "reward": {
846
+ "step_reward": -34.86,
847
+ "cumulative_reward": -0.64,
848
+ "components": {
849
+ "central_replenishment_cost": -4.4,
850
+ "central_replenishment_bonus": 0.5,
851
+ "fulfilled_order_value": 44.0,
852
+ "delivery_cost": -3.0,
853
+ "holding_cost": -5.72,
854
+ "fairness_penalty": -66.24
855
+ }
856
+ },
857
+ "events": [
858
+ "central depot sent 2 rice_bag_5kg to riverside",
859
+ "south local agent fulfilled 1 insulin_pack",
860
+ "riverside local agent fulfilled 2 rice_bag_5kg"
861
+ ],
862
+ "components": {
863
+ "central_replenishment_cost": -4.4,
864
+ "central_replenishment_bonus": 0.5,
865
+ "fulfilled_order_value": 44.0,
866
+ "delivery_cost": -3.0,
867
+ "holding_cost": -5.72,
868
+ "fairness_penalty": -66.24
869
+ },
870
+ "done": false
871
+ },
872
+ {
873
+ "round": 18,
874
+ "action": {
875
+ "fulfillments": [],
876
+ "central_procurements": [
877
+ {
878
+ "sku": "insulin_pack",
879
+ "units": 2
880
+ }
881
+ ],
882
+ "central_replenishments": [
883
+ {
884
+ "to_warehouse": "south",
885
+ "sku": "insulin_pack",
886
+ "units": 1
887
+ }
888
+ ],
889
+ "inventory_transfers": [],
890
+ "driver_loans": [],
891
+ "offer_matches": [],
892
+ "priority_policy": [],
893
+ "defer_orders": [],
894
+ "coalition_deals": []
895
+ },
896
+ "reward": {
897
+ "step_reward": -41.015,
898
+ "cumulative_reward": -41.655,
899
+ "components": {
900
+ "central_procurement_cost": -16.0,
901
+ "strategic_procurement_bonus": 0.7,
902
+ "central_replenishment_cost": -2.2,
903
+ "central_replenishment_bonus": 0.25,
904
+ "fulfilled_order_value": 52.0,
905
+ "delivery_cost": -4.0,
906
+ "holding_cost": -5.525,
907
+ "fairness_penalty": -66.24
908
+ }
909
+ },
910
+ "events": [
911
+ "central bought 2 insulin_pack for depot arrival at round 21",
912
+ "central depot sent 1 insulin_pack to south",
913
+ "south local agent fulfilled 2 fresh_milk",
914
+ "riverside local agent fulfilled 2 fresh_milk"
915
+ ],
916
+ "components": {
917
+ "central_procurement_cost": -16.0,
918
+ "strategic_procurement_bonus": 0.7,
919
+ "central_replenishment_cost": -2.2,
920
+ "central_replenishment_bonus": 0.25,
921
+ "fulfilled_order_value": 52.0,
922
+ "delivery_cost": -4.0,
923
+ "holding_cost": -5.525,
924
+ "fairness_penalty": -66.24
925
+ },
926
+ "done": false
927
+ },
928
+ {
929
+ "round": 19,
930
+ "action": {
931
+ "fulfillments": [],
932
+ "central_procurements": [],
933
+ "central_replenishments": [
934
+ {
935
+ "to_warehouse": "south",
936
+ "sku": "rice_bag_5kg",
937
+ "units": 2
938
+ }
939
+ ],
940
+ "inventory_transfers": [],
941
+ "driver_loans": [],
942
+ "offer_matches": [],
943
+ "priority_policy": [],
944
+ "defer_orders": [],
945
+ "coalition_deals": []
946
+ },
947
+ "reward": {
948
+ "step_reward": -47.76,
949
+ "cumulative_reward": -89.415,
950
+ "components": {
951
+ "central_replenishment_cost": -4.4,
952
+ "central_replenishment_bonus": 0.5,
953
+ "fulfilled_order_value": 33.0,
954
+ "delivery_cost": -3.0,
955
+ "holding_cost": -5.46,
956
+ "fairness_penalty": -68.4
957
+ }
958
+ },
959
+ "events": [
960
+ "central depot sent 2 rice_bag_5kg to south",
961
+ "south local agent fulfilled 3 rice_bag_5kg"
962
+ ],
963
+ "components": {
964
+ "central_replenishment_cost": -4.4,
965
+ "central_replenishment_bonus": 0.5,
966
+ "fulfilled_order_value": 33.0,
967
+ "delivery_cost": -3.0,
968
+ "holding_cost": -5.46,
969
+ "fairness_penalty": -68.4
970
+ },
971
+ "done": false
972
+ },
973
+ {
974
+ "round": 20,
975
+ "action": {
976
+ "fulfillments": [],
977
+ "central_procurements": [],
978
+ "central_replenishments": [
979
+ {
980
+ "to_warehouse": "south",
981
+ "sku": "fresh_milk",
982
+ "units": 2
983
+ }
984
+ ],
985
+ "inventory_transfers": [],
986
+ "driver_loans": [],
987
+ "offer_matches": [],
988
+ "priority_policy": [],
989
+ "defer_orders": [],
990
+ "coalition_deals": []
991
+ },
992
+ "reward": {
993
+ "step_reward": -61.495,
994
+ "cumulative_reward": -150.91,
995
+ "components": {
996
+ "central_replenishment_cost": -4.4,
997
+ "central_replenishment_bonus": 0.5,
998
+ "fulfilled_order_value": 69.0,
999
+ "delivery_cost": -3.0,
1000
+ "stockout_penalty": -46.2,
1001
+ "holding_cost": -5.395,
1002
+ "fairness_penalty": -72.0
1003
+ }
1004
+ },
1005
+ "events": [
1006
+ "central depot sent 2 fresh_milk to south",
1007
+ "east local agent fulfilled 1 fresh_milk",
1008
+ "west local agent fulfilled 2 usb_c_charger",
1009
+ "o35 expired"
1010
+ ],
1011
+ "components": {
1012
+ "central_replenishment_cost": -4.4,
1013
+ "central_replenishment_bonus": 0.5,
1014
+ "fulfilled_order_value": 69.0,
1015
+ "delivery_cost": -3.0,
1016
+ "stockout_penalty": -46.2,
1017
+ "holding_cost": -5.395,
1018
+ "fairness_penalty": -72.0
1019
+ },
1020
+ "done": false
1021
+ },
1022
+ {
1023
+ "round": 21,
1024
+ "action": {
1025
+ "fulfillments": [],
1026
+ "central_procurements": [
1027
+ {
1028
+ "sku": "fresh_milk",
1029
+ "units": 2
1030
+ }
1031
+ ],
1032
+ "central_replenishments": [
1033
+ {
1034
+ "to_warehouse": "riverside",
1035
+ "sku": "rice_bag_5kg",
1036
+ "units": 2
1037
+ }
1038
+ ],
1039
+ "inventory_transfers": [],
1040
+ "driver_loans": [],
1041
+ "offer_matches": [],
1042
+ "priority_policy": [],
1043
+ "defer_orders": [],
1044
+ "coalition_deals": []
1045
+ },
1046
+ "reward": {
1047
+ "step_reward": 30.73,
1048
+ "cumulative_reward": -120.18,
1049
+ "components": {
1050
+ "central_procurement_cost": -8.0,
1051
+ "strategic_procurement_bonus": 0.7,
1052
+ "central_replenishment_cost": -4.4,
1053
+ "central_replenishment_bonus": 0.5,
1054
+ "fulfilled_order_value": 126.0,
1055
+ "delivery_cost": -7.0,
1056
+ "holding_cost": -5.07,
1057
+ "fairness_penalty": -72.0
1058
+ }
1059
+ },
1060
+ "events": [
1061
+ "central bought 2 fresh_milk for depot arrival at round 24",
1062
+ "central depot sent 2 rice_bag_5kg to riverside",
1063
+ "west local agent fulfilled 3 fresh_milk",
1064
+ "riverside local agent fulfilled 2 rice_bag_5kg",
1065
+ "campus local agent fulfilled 2 insulin_pack"
1066
+ ],
1067
+ "components": {
1068
+ "central_procurement_cost": -8.0,
1069
+ "strategic_procurement_bonus": 0.7,
1070
+ "central_replenishment_cost": -4.4,
1071
+ "central_replenishment_bonus": 0.5,
1072
+ "fulfilled_order_value": 126.0,
1073
+ "delivery_cost": -7.0,
1074
+ "holding_cost": -5.07,
1075
+ "fairness_penalty": -72.0
1076
+ },
1077
+ "done": false
1078
+ },
1079
+ {
1080
+ "round": 22,
1081
+ "action": {
1082
+ "fulfillments": [],
1083
+ "central_procurements": [
1084
+ {
1085
+ "sku": "rice_bag_5kg",
1086
+ "units": 2
1087
+ }
1088
+ ],
1089
+ "central_replenishments": [
1090
+ {
1091
+ "to_warehouse": "campus",
1092
+ "sku": "insulin_pack",
1093
+ "units": 2
1094
+ }
1095
+ ],
1096
+ "inventory_transfers": [],
1097
+ "driver_loans": [],
1098
+ "offer_matches": [],
1099
+ "priority_policy": [],
1100
+ "defer_orders": [],
1101
+ "coalition_deals": []
1102
+ },
1103
+ "reward": {
1104
+ "step_reward": -51.5,
1105
+ "cumulative_reward": -171.68,
1106
+ "components": {
1107
+ "central_procurement_cost": -6.4,
1108
+ "strategic_procurement_bonus": 0.7,
1109
+ "central_replenishment_cost": -4.4,
1110
+ "central_replenishment_bonus": 0.5,
1111
+ "fulfilled_order_value": 52.0,
1112
+ "delivery_cost": -4.0,
1113
+ "holding_cost": -4.94,
1114
+ "fairness_penalty": -84.96
1115
+ }
1116
+ },
1117
+ "events": [
1118
+ "central bought 2 rice_bag_5kg for depot arrival at round 25",
1119
+ "central depot sent 2 insulin_pack to campus",
1120
+ "east local agent fulfilled 3 rice_bag_5kg",
1121
+ "west local agent fulfilled 1 rice_bag_5kg"
1122
+ ],
1123
+ "components": {
1124
+ "central_procurement_cost": -6.4,
1125
+ "strategic_procurement_bonus": 0.7,
1126
+ "central_replenishment_cost": -4.4,
1127
+ "central_replenishment_bonus": 0.5,
1128
+ "fulfilled_order_value": 52.0,
1129
+ "delivery_cost": -4.0,
1130
+ "holding_cost": -4.94,
1131
+ "fairness_penalty": -84.96
1132
+ },
1133
+ "done": false
1134
+ },
1135
+ {
1136
+ "round": 23,
1137
+ "action": {
1138
+ "fulfillments": [],
1139
+ "central_procurements": [],
1140
+ "central_replenishments": [
1141
+ {
1142
+ "to_warehouse": "east",
1143
+ "sku": "usb_c_charger",
1144
+ "units": 1
1145
+ }
1146
+ ],
1147
+ "inventory_transfers": [],
1148
+ "driver_loans": [],
1149
+ "offer_matches": [],
1150
+ "priority_policy": [],
1151
+ "defer_orders": [],
1152
+ "coalition_deals": []
1153
+ },
1154
+ "reward": {
1155
+ "step_reward": -2.47,
1156
+ "cumulative_reward": -174.15,
1157
+ "components": {
1158
+ "central_replenishment_cost": -2.2,
1159
+ "central_replenishment_bonus": 0.25,
1160
+ "fulfilled_order_value": 79.0,
1161
+ "delivery_cost": -5.0,
1162
+ "holding_cost": -4.68,
1163
+ "fairness_penalty": -69.84
1164
+ }
1165
+ },
1166
+ "events": [
1167
+ "central depot sent 1 usb_c_charger to east",
1168
+ "central local agent fulfilled 3 fresh_milk",
1169
+ "campus local agent fulfilled 2 fresh_milk"
1170
+ ],
1171
+ "components": {
1172
+ "central_replenishment_cost": -2.2,
1173
+ "central_replenishment_bonus": 0.25,
1174
+ "fulfilled_order_value": 79.0,
1175
+ "delivery_cost": -5.0,
1176
+ "holding_cost": -4.68,
1177
+ "fairness_penalty": -69.84
1178
+ },
1179
+ "done": false
1180
+ },
1181
+ {
1182
+ "round": 24,
1183
+ "action": {
1184
+ "fulfillments": [],
1185
+ "central_procurements": [],
1186
+ "central_replenishments": [
1187
+ {
1188
+ "to_warehouse": "south",
1189
+ "sku": "usb_c_charger",
1190
+ "units": 2
1191
+ }
1192
+ ],
1193
+ "inventory_transfers": [],
1194
+ "driver_loans": [],
1195
+ "offer_matches": [],
1196
+ "priority_policy": [],
1197
+ "defer_orders": [],
1198
+ "coalition_deals": []
1199
+ },
1200
+ "reward": {
1201
+ "step_reward": -147.85,
1202
+ "cumulative_reward": -322.0,
1203
+ "components": {
1204
+ "central_replenishment_cost": -4.4,
1205
+ "central_replenishment_bonus": 0.5,
1206
+ "stockout_penalty": -69.3,
1207
+ "holding_cost": -4.81,
1208
+ "fairness_penalty": -69.84
1209
+ }
1210
+ },
1211
+ "events": [
1212
+ "central depot sent 2 usb_c_charger to south",
1213
+ "o43 expired"
1214
+ ],
1215
+ "components": {
1216
+ "central_replenishment_cost": -4.4,
1217
+ "central_replenishment_bonus": 0.5,
1218
+ "stockout_penalty": -69.3,
1219
+ "holding_cost": -4.81,
1220
+ "fairness_penalty": -69.84
1221
+ },
1222
+ "done": false
1223
+ },
1224
+ {
1225
+ "round": 25,
1226
+ "action": {
1227
+ "fulfillments": [],
1228
+ "central_procurements": [
1229
+ {
1230
+ "sku": "fresh_milk",
1231
+ "units": 2
1232
+ }
1233
+ ],
1234
+ "central_replenishments": [
1235
+ {
1236
+ "to_warehouse": "east",
1237
+ "sku": "fresh_milk",
1238
+ "units": 2
1239
+ }
1240
+ ],
1241
+ "inventory_transfers": [],
1242
+ "driver_loans": [],
1243
+ "offer_matches": [],
1244
+ "priority_policy": [],
1245
+ "defer_orders": [],
1246
+ "coalition_deals": []
1247
+ },
1248
+ "reward": {
1249
+ "step_reward": -71.195,
1250
+ "cumulative_reward": -393.195,
1251
+ "components": {
1252
+ "central_procurement_cost": -8.0,
1253
+ "strategic_procurement_bonus": 0.7,
1254
+ "central_replenishment_cost": -4.4,
1255
+ "central_replenishment_bonus": 0.5,
1256
+ "fulfilled_order_value": 24.0,
1257
+ "delivery_cost": -1.0,
1258
+ "holding_cost": -4.875,
1259
+ "fairness_penalty": -78.12
1260
+ }
1261
+ },
1262
+ "events": [
1263
+ "central bought 2 fresh_milk for depot arrival at round 28",
1264
+ "central depot sent 2 fresh_milk to east",
1265
+ "east local agent fulfilled 1 insulin_pack"
1266
+ ],
1267
+ "components": {
1268
+ "central_procurement_cost": -8.0,
1269
+ "strategic_procurement_bonus": 0.7,
1270
+ "central_replenishment_cost": -4.4,
1271
+ "central_replenishment_bonus": 0.5,
1272
+ "fulfilled_order_value": 24.0,
1273
+ "delivery_cost": -1.0,
1274
+ "holding_cost": -4.875,
1275
+ "fairness_penalty": -78.12
1276
+ },
1277
+ "done": false
1278
+ },
1279
+ {
1280
+ "round": 26,
1281
+ "action": {
1282
+ "fulfillments": [],
1283
+ "central_procurements": [
1284
+ {
1285
+ "sku": "rice_bag_5kg",
1286
+ "units": 2
1287
+ }
1288
+ ],
1289
+ "central_replenishments": [
1290
+ {
1291
+ "to_warehouse": "riverside",
1292
+ "sku": "rice_bag_5kg",
1293
+ "units": 2
1294
+ }
1295
+ ],
1296
+ "inventory_transfers": [],
1297
+ "driver_loans": [],
1298
+ "offer_matches": [],
1299
+ "priority_policy": [],
1300
+ "defer_orders": [],
1301
+ "coalition_deals": []
1302
+ },
1303
+ "reward": {
1304
+ "step_reward": -36.8,
1305
+ "cumulative_reward": -429.995,
1306
+ "components": {
1307
+ "central_procurement_cost": -6.4,
1308
+ "strategic_procurement_bonus": 0.7,
1309
+ "central_replenishment_cost": -4.4,
1310
+ "central_replenishment_bonus": 0.5,
1311
+ "fulfilled_order_value": 100.0,
1312
+ "delivery_cost": -7.0,
1313
+ "stockout_penalty": -47.25,
1314
+ "holding_cost": -4.55,
1315
+ "fairness_penalty": -68.4
1316
+ }
1317
+ },
1318
+ "events": [
1319
+ "central bought 2 rice_bag_5kg for depot arrival at round 29",
1320
+ "central depot sent 2 rice_bag_5kg to riverside",
1321
+ "south local agent fulfilled 2 rice_bag_5kg",
1322
+ "central local agent fulfilled 2 rice_bag_5kg",
1323
+ "riverside local agent fulfilled 3 rice_bag_5kg",
1324
+ "o48 expired"
1325
+ ],
1326
+ "components": {
1327
+ "central_procurement_cost": -6.4,
1328
+ "strategic_procurement_bonus": 0.7,
1329
+ "central_replenishment_cost": -4.4,
1330
+ "central_replenishment_bonus": 0.5,
1331
+ "fulfilled_order_value": 100.0,
1332
+ "delivery_cost": -7.0,
1333
+ "stockout_penalty": -47.25,
1334
+ "holding_cost": -4.55,
1335
+ "fairness_penalty": -68.4
1336
+ },
1337
+ "done": false
1338
+ },
1339
+ {
1340
+ "round": 27,
1341
+ "action": {
1342
+ "fulfillments": [],
1343
+ "central_procurements": [],
1344
+ "central_replenishments": [
1345
+ {
1346
+ "to_warehouse": "campus",
1347
+ "sku": "usb_c_charger",
1348
+ "units": 1
1349
+ }
1350
+ ],
1351
+ "inventory_transfers": [],
1352
+ "driver_loans": [],
1353
+ "offer_matches": [],
1354
+ "priority_policy": [],
1355
+ "defer_orders": [],
1356
+ "coalition_deals": []
1357
+ },
1358
+ "reward": {
1359
+ "step_reward": 15.865,
1360
+ "cumulative_reward": -414.13,
1361
+ "components": {
1362
+ "central_replenishment_cost": -2.2,
1363
+ "central_replenishment_bonus": 0.25,
1364
+ "fulfilled_order_value": 86.0,
1365
+ "delivery_cost": -6.0,
1366
+ "holding_cost": -4.225,
1367
+ "fairness_penalty": -57.96
1368
+ }
1369
+ },
1370
+ "events": [
1371
+ "central depot sent 1 usb_c_charger to campus",
1372
+ "east local agent fulfilled 1 fresh_milk",
1373
+ "west local agent fulfilled 1 rice_bag_5kg",
1374
+ "central local agent fulfilled 4 rice_bag_5kg"
1375
+ ],
1376
+ "components": {
1377
+ "central_replenishment_cost": -2.2,
1378
+ "central_replenishment_bonus": 0.25,
1379
+ "fulfilled_order_value": 86.0,
1380
+ "delivery_cost": -6.0,
1381
+ "holding_cost": -4.225,
1382
+ "fairness_penalty": -57.96
1383
+ },
1384
+ "done": false
1385
+ },
1386
+ {
1387
+ "round": 28,
1388
+ "action": {
1389
+ "fulfillments": [],
1390
+ "central_procurements": [
1391
+ {
1392
+ "sku": "insulin_pack",
1393
+ "units": 2
1394
+ }
1395
+ ],
1396
+ "central_replenishments": [],
1397
+ "inventory_transfers": [],
1398
+ "driver_loans": [],
1399
+ "offer_matches": [],
1400
+ "priority_policy": [],
1401
+ "defer_orders": [],
1402
+ "coalition_deals": []
1403
+ },
1404
+ "reward": {
1405
+ "step_reward": -50.355,
1406
+ "cumulative_reward": -464.485,
1407
+ "components": {
1408
+ "central_procurement_cost": -16.0,
1409
+ "strategic_procurement_bonus": 0.7,
1410
+ "fulfilled_order_value": 29.0,
1411
+ "delivery_cost": -2.0,
1412
+ "holding_cost": -4.095,
1413
+ "fairness_penalty": -57.96
1414
+ }
1415
+ },
1416
+ "events": [
1417
+ "central bought 2 insulin_pack for depot arrival at round 31",
1418
+ "central local agent fulfilled 2 rice_bag_5kg"
1419
+ ],
1420
+ "components": {
1421
+ "central_procurement_cost": -16.0,
1422
+ "strategic_procurement_bonus": 0.7,
1423
+ "fulfilled_order_value": 29.0,
1424
+ "delivery_cost": -2.0,
1425
+ "holding_cost": -4.095,
1426
+ "fairness_penalty": -57.96
1427
+ },
1428
+ "done": false
1429
+ },
1430
+ {
1431
+ "round": 29,
1432
+ "action": {
1433
+ "fulfillments": [],
1434
+ "central_procurements": [],
1435
+ "central_replenishments": [
1436
+ {
1437
+ "to_warehouse": "central",
1438
+ "sku": "fresh_milk",
1439
+ "units": 2
1440
+ },
1441
+ {
1442
+ "to_warehouse": "north",
1443
+ "sku": "fresh_milk",
1444
+ "units": 2
1445
+ }
1446
+ ],
1447
+ "inventory_transfers": [],
1448
+ "driver_loans": [],
1449
+ "offer_matches": [],
1450
+ "priority_policy": [],
1451
+ "defer_orders": [],
1452
+ "coalition_deals": []
1453
+ },
1454
+ "reward": {
1455
+ "step_reward": -41.1,
1456
+ "cumulative_reward": -505.585,
1457
+ "components": {
1458
+ "central_replenishment_cost": -4.4,
1459
+ "central_replenishment_bonus": 0.5,
1460
+ "invalid_action_penalty": -4.0,
1461
+ "fulfilled_order_value": 59.0,
1462
+ "delivery_cost": -3.0,
1463
+ "stockout_penalty": -30.45,
1464
+ "holding_cost": -4.03,
1465
+ "fairness_penalty": -54.72
1466
+ }
1467
+ },
1468
+ "events": [
1469
+ "central depot sent 2 fresh_milk to central",
1470
+ "central depot lacked fresh_milk",
1471
+ "north local agent fulfilled 2 fresh_milk",
1472
+ "south local agent fulfilled 1 insulin_pack",
1473
+ "o53 expired"
1474
+ ],
1475
+ "components": {
1476
+ "central_replenishment_cost": -4.4,
1477
+ "central_replenishment_bonus": 0.5,
1478
+ "invalid_action_penalty": -4.0,
1479
+ "fulfilled_order_value": 59.0,
1480
+ "delivery_cost": -3.0,
1481
+ "stockout_penalty": -30.45,
1482
+ "holding_cost": -4.03,
1483
+ "fairness_penalty": -54.72
1484
+ },
1485
+ "done": false
1486
+ },
1487
+ {
1488
+ "round": 30,
1489
+ "action": {
1490
+ "fulfillments": [],
1491
+ "central_procurements": [
1492
+ {
1493
+ "sku": "rice_bag_5kg",
1494
+ "units": 2
1495
+ }
1496
+ ],
1497
+ "central_replenishments": [
1498
+ {
1499
+ "to_warehouse": "west",
1500
+ "sku": "rice_bag_5kg",
1501
+ "units": 2
1502
+ }
1503
+ ],
1504
+ "inventory_transfers": [],
1505
+ "driver_loans": [],
1506
+ "offer_matches": [],
1507
+ "priority_policy": [],
1508
+ "defer_orders": [],
1509
+ "coalition_deals": []
1510
+ },
1511
+ "reward": {
1512
+ "step_reward": 34.785,
1513
+ "cumulative_reward": -470.8,
1514
+ "components": {
1515
+ "central_procurement_cost": -6.4,
1516
+ "strategic_procurement_bonus": 0.7,
1517
+ "central_replenishment_cost": -4.4,
1518
+ "central_replenishment_bonus": 0.5,
1519
+ "fulfilled_order_value": 97.5,
1520
+ "delivery_cost": -5.0,
1521
+ "holding_cost": -3.835,
1522
+ "fairness_penalty": -44.28
1523
+ }
1524
+ },
1525
+ "events": [
1526
+ "central bought 2 rice_bag_5kg for depot arrival at round 33",
1527
+ "central depot sent 2 rice_bag_5kg to west",
1528
+ "north local agent fulfilled 2 insulin_pack",
1529
+ "riverside local agent fulfilled 3 fresh_milk"
1530
+ ],
1531
+ "components": {
1532
+ "central_procurement_cost": -6.4,
1533
+ "strategic_procurement_bonus": 0.7,
1534
+ "central_replenishment_cost": -4.4,
1535
+ "central_replenishment_bonus": 0.5,
1536
+ "fulfilled_order_value": 97.5,
1537
+ "delivery_cost": -5.0,
1538
+ "holding_cost": -3.835,
1539
+ "fairness_penalty": -44.28
1540
+ },
1541
+ "done": false
1542
+ },
1543
+ {
1544
+ "round": 31,
1545
+ "action": {
1546
+ "fulfillments": [],
1547
+ "central_procurements": [
1548
+ {
1549
+ "sku": "fresh_milk",
1550
+ "units": 2
1551
+ }
1552
+ ],
1553
+ "central_replenishments": [],
1554
+ "inventory_transfers": [],
1555
+ "driver_loans": [],
1556
+ "offer_matches": [],
1557
+ "priority_policy": [],
1558
+ "defer_orders": [],
1559
+ "coalition_deals": []
1560
+ },
1561
+ "reward": {
1562
+ "step_reward": -7.22,
1563
+ "cumulative_reward": -478.02,
1564
+ "components": {
1565
+ "central_procurement_cost": -8.0,
1566
+ "strategic_procurement_bonus": 0.7,
1567
+ "fulfilled_order_value": 51.0,
1568
+ "delivery_cost": -3.0,
1569
+ "holding_cost": -3.64,
1570
+ "fairness_penalty": -44.28
1571
+ }
1572
+ },
1573
+ "events": [
1574
+ "central bought 2 fresh_milk for depot arrival at round 34",
1575
+ "west local agent fulfilled 3 fresh_milk"
1576
+ ],
1577
+ "components": {
1578
+ "central_procurement_cost": -8.0,
1579
+ "strategic_procurement_bonus": 0.7,
1580
+ "fulfilled_order_value": 51.0,
1581
+ "delivery_cost": -3.0,
1582
+ "holding_cost": -3.64,
1583
+ "fairness_penalty": -44.28
1584
+ },
1585
+ "done": false
1586
+ },
1587
+ {
1588
+ "round": 32,
1589
+ "action": {
1590
+ "fulfillments": [],
1591
+ "central_procurements": [
1592
+ {
1593
+ "sku": "insulin_pack",
1594
+ "units": 2
1595
+ }
1596
+ ],
1597
+ "central_replenishments": [
1598
+ {
1599
+ "to_warehouse": "central",
1600
+ "sku": "insulin_pack",
1601
+ "units": 2
1602
+ },
1603
+ {
1604
+ "to_warehouse": "north",
1605
+ "sku": "insulin_pack",
1606
+ "units": 1
1607
+ }
1608
+ ],
1609
+ "inventory_transfers": [],
1610
+ "driver_loans": [],
1611
+ "offer_matches": [],
1612
+ "priority_policy": [],
1613
+ "defer_orders": [],
1614
+ "coalition_deals": []
1615
+ },
1616
+ "reward": {
1617
+ "step_reward": 2.65,
1618
+ "cumulative_reward": -475.37,
1619
+ "components": {
1620
+ "central_procurement_cost": -16.0,
1621
+ "strategic_procurement_bonus": 0.7,
1622
+ "central_replenishment_cost": -4.4,
1623
+ "central_replenishment_bonus": 0.5,
1624
+ "invalid_action_penalty": -4.0,
1625
+ "fulfilled_order_value": 96.0,
1626
+ "delivery_cost": -4.0,
1627
+ "late_delivery_penalty": -21.6,
1628
+ "holding_cost": -3.51,
1629
+ "fairness_penalty": -41.04
1630
+ }
1631
+ },
1632
+ "events": [
1633
+ "central bought 2 insulin_pack for depot arrival at round 35",
1634
+ "central depot sent 2 insulin_pack to central",
1635
+ "central depot lacked insulin_pack",
1636
+ "central local agent fulfilled 4 insulin_pack"
1637
+ ],
1638
+ "components": {
1639
+ "central_procurement_cost": -16.0,
1640
+ "strategic_procurement_bonus": 0.7,
1641
+ "central_replenishment_cost": -4.4,
1642
+ "central_replenishment_bonus": 0.5,
1643
+ "invalid_action_penalty": -4.0,
1644
+ "fulfilled_order_value": 96.0,
1645
+ "delivery_cost": -4.0,
1646
+ "late_delivery_penalty": -21.6,
1647
+ "holding_cost": -3.51,
1648
+ "fairness_penalty": -41.04
1649
+ },
1650
+ "done": false
1651
+ },
1652
+ {
1653
+ "round": 33,
1654
+ "action": {
1655
+ "fulfillments": [],
1656
+ "central_procurements": [],
1657
+ "central_replenishments": [
1658
+ {
1659
+ "to_warehouse": "north",
1660
+ "sku": "usb_c_charger",
1661
+ "units": 1
1662
+ }
1663
+ ],
1664
+ "inventory_transfers": [],
1665
+ "driver_loans": [],
1666
+ "offer_matches": [],
1667
+ "priority_policy": [],
1668
+ "defer_orders": [],
1669
+ "coalition_deals": []
1670
+ },
1671
+ "reward": {
1672
+ "step_reward": 7.13,
1673
+ "cumulative_reward": -468.24,
1674
+ "components": {
1675
+ "central_replenishment_cost": -2.2,
1676
+ "central_replenishment_bonus": 0.25,
1677
+ "fulfilled_order_value": 56.5,
1678
+ "delivery_cost": -3.0,
1679
+ "holding_cost": -3.38,
1680
+ "fairness_penalty": -41.04
1681
+ }
1682
+ },
1683
+ "events": [
1684
+ "central depot sent 1 usb_c_charger to north",
1685
+ "north local agent fulfilled 1 usb_c_charger",
1686
+ "south local agent fulfilled 2 rice_bag_5kg"
1687
+ ],
1688
+ "components": {
1689
+ "central_replenishment_cost": -2.2,
1690
+ "central_replenishment_bonus": 0.25,
1691
+ "fulfilled_order_value": 56.5,
1692
+ "delivery_cost": -3.0,
1693
+ "holding_cost": -3.38,
1694
+ "fairness_penalty": -41.04
1695
+ },
1696
+ "done": false
1697
+ },
1698
+ {
1699
+ "round": 34,
1700
+ "action": {
1701
+ "fulfillments": [],
1702
+ "central_procurements": [],
1703
+ "central_replenishments": [
1704
+ {
1705
+ "to_warehouse": "east",
1706
+ "sku": "rice_bag_5kg",
1707
+ "units": 2
1708
+ }
1709
+ ],
1710
+ "inventory_transfers": [],
1711
+ "driver_loans": [],
1712
+ "offer_matches": [],
1713
+ "priority_policy": [],
1714
+ "defer_orders": [],
1715
+ "coalition_deals": []
1716
+ },
1717
+ "reward": {
1718
+ "step_reward": -23.445,
1719
+ "cumulative_reward": -491.685,
1720
+ "components": {
1721
+ "central_replenishment_cost": -4.4,
1722
+ "central_replenishment_bonus": 0.5,
1723
+ "fulfilled_order_value": 72.0,
1724
+ "delivery_cost": -3.0,
1725
+ "stockout_penalty": -47.25,
1726
+ "holding_cost": -3.315,
1727
+ "fairness_penalty": -37.98
1728
+ }
1729
+ },
1730
+ "events": [
1731
+ "central depot sent 2 rice_bag_5kg to east",
1732
+ "campus local agent fulfilled 3 insulin_pack",
1733
+ "o68 expired"
1734
+ ],
1735
+ "components": {
1736
+ "central_replenishment_cost": -4.4,
1737
+ "central_replenishment_bonus": 0.5,
1738
+ "fulfilled_order_value": 72.0,
1739
+ "delivery_cost": -3.0,
1740
+ "stockout_penalty": -47.25,
1741
+ "holding_cost": -3.315,
1742
+ "fairness_penalty": -37.98
1743
+ },
1744
+ "done": false
1745
+ },
1746
+ {
1747
+ "round": 35,
1748
+ "action": {
1749
+ "fulfillments": [],
1750
+ "central_procurements": [],
1751
+ "central_replenishments": [
1752
+ {
1753
+ "to_warehouse": "west",
1754
+ "sku": "fresh_milk",
1755
+ "units": 2
1756
+ }
1757
+ ],
1758
+ "inventory_transfers": [],
1759
+ "driver_loans": [],
1760
+ "offer_matches": [],
1761
+ "priority_policy": [],
1762
+ "defer_orders": [],
1763
+ "coalition_deals": []
1764
+ },
1765
+ "reward": {
1766
+ "step_reward": -64.445,
1767
+ "cumulative_reward": -556.13,
1768
+ "components": {
1769
+ "central_replenishment_cost": -4.4,
1770
+ "central_replenishment_bonus": 0.5,
1771
+ "fulfilled_order_value": 30.0,
1772
+ "delivery_cost": -2.0,
1773
+ "stockout_penalty": -47.25,
1774
+ "holding_cost": -3.315,
1775
+ "fairness_penalty": -37.98
1776
+ }
1777
+ },
1778
+ "events": [
1779
+ "central depot sent 2 fresh_milk to west",
1780
+ "west local agent fulfilled 2 fresh_milk",
1781
+ "o64 expired"
1782
+ ],
1783
+ "components": {
1784
+ "central_replenishment_cost": -4.4,
1785
+ "central_replenishment_bonus": 0.5,
1786
+ "fulfilled_order_value": 30.0,
1787
+ "delivery_cost": -2.0,
1788
+ "stockout_penalty": -47.25,
1789
+ "holding_cost": -3.315,
1790
+ "fairness_penalty": -37.98
1791
+ },
1792
+ "done": false
1793
+ },
1794
+ {
1795
+ "round": 36,
1796
+ "action": {
1797
+ "fulfillments": [],
1798
+ "central_procurements": [],
1799
+ "central_replenishments": [
1800
+ {
1801
+ "to_warehouse": "north",
1802
+ "sku": "insulin_pack",
1803
+ "units": 2
1804
+ }
1805
+ ],
1806
+ "inventory_transfers": [],
1807
+ "driver_loans": [],
1808
+ "offer_matches": [],
1809
+ "priority_policy": [],
1810
+ "defer_orders": [],
1811
+ "coalition_deals": []
1812
+ },
1813
+ "reward": {
1814
+ "step_reward": 0.87,
1815
+ "cumulative_reward": -555.26,
1816
+ "components": {
1817
+ "central_replenishment_cost": -4.4,
1818
+ "central_replenishment_bonus": 0.5,
1819
+ "fulfilled_order_value": 49.0,
1820
+ "delivery_cost": -3.0,
1821
+ "holding_cost": -3.25,
1822
+ "fairness_penalty": -37.98
1823
+ }
1824
+ },
1825
+ "events": [
1826
+ "central depot sent 2 insulin_pack to north",
1827
+ "central local agent fulfilled 2 fresh_milk",
1828
+ "campus local agent fulfilled 1 rice_bag_5kg"
1829
+ ],
1830
+ "components": {
1831
+ "central_replenishment_cost": -4.4,
1832
+ "central_replenishment_bonus": 0.5,
1833
+ "fulfilled_order_value": 49.0,
1834
+ "delivery_cost": -3.0,
1835
+ "holding_cost": -3.25,
1836
+ "fairness_penalty": -37.98
1837
+ },
1838
+ "done": false
1839
+ },
1840
+ {
1841
+ "round": 37,
1842
+ "action": {
1843
+ "fulfillments": [],
1844
+ "central_procurements": [],
1845
+ "central_replenishments": [
1846
+ {
1847
+ "to_warehouse": "south",
1848
+ "sku": "usb_c_charger",
1849
+ "units": 1
1850
+ }
1851
+ ],
1852
+ "inventory_transfers": [],
1853
+ "driver_loans": [],
1854
+ "offer_matches": [],
1855
+ "priority_policy": [],
1856
+ "defer_orders": [],
1857
+ "coalition_deals": []
1858
+ },
1859
+ "reward": {
1860
+ "step_reward": -27.225,
1861
+ "cumulative_reward": -582.485,
1862
+ "components": {
1863
+ "central_replenishment_cost": -2.2,
1864
+ "central_replenishment_bonus": 0.25,
1865
+ "fulfilled_order_value": 110.0,
1866
+ "delivery_cost": -4.0,
1867
+ "stockout_penalty": -54.6,
1868
+ "holding_cost": -3.055,
1869
+ "fairness_penalty": -73.62
1870
+ }
1871
+ },
1872
+ "events": [
1873
+ "central depot sent 1 usb_c_charger to south",
1874
+ "south local agent fulfilled 4 usb_c_charger",
1875
+ "o71 expired"
1876
+ ],
1877
+ "components": {
1878
+ "central_replenishment_cost": -2.2,
1879
+ "central_replenishment_bonus": 0.25,
1880
+ "fulfilled_order_value": 110.0,
1881
+ "delivery_cost": -4.0,
1882
+ "stockout_penalty": -54.6,
1883
+ "holding_cost": -3.055,
1884
+ "fairness_penalty": -73.62
1885
+ },
1886
+ "done": false
1887
+ },
1888
+ {
1889
+ "round": 38,
1890
+ "action": {
1891
+ "fulfillments": [],
1892
+ "central_procurements": [],
1893
+ "central_replenishments": [],
1894
+ "inventory_transfers": [],
1895
+ "driver_loans": [],
1896
+ "offer_matches": [],
1897
+ "priority_policy": [],
1898
+ "defer_orders": [],
1899
+ "coalition_deals": []
1900
+ },
1901
+ "reward": {
1902
+ "step_reward": -259.375,
1903
+ "cumulative_reward": -841.86,
1904
+ "components": {
1905
+ "stockout_penalty": -182.7,
1906
+ "holding_cost": -3.055,
1907
+ "fairness_penalty": -73.62
1908
+ }
1909
+ },
1910
+ "events": [
1911
+ "o72 expired",
1912
+ "o73 expired"
1913
+ ],
1914
+ "components": {
1915
+ "stockout_penalty": -182.7,
1916
+ "holding_cost": -3.055,
1917
+ "fairness_penalty": -73.62
1918
+ },
1919
+ "done": false
1920
+ },
1921
+ {
1922
+ "round": 39,
1923
+ "action": {
1924
+ "fulfillments": [],
1925
+ "central_procurements": [],
1926
+ "central_replenishments": [],
1927
+ "inventory_transfers": [],
1928
+ "driver_loans": [],
1929
+ "offer_matches": [],
1930
+ "priority_policy": [],
1931
+ "defer_orders": [],
1932
+ "coalition_deals": []
1933
+ },
1934
+ "reward": {
1935
+ "step_reward": -76.675,
1936
+ "cumulative_reward": -918.535,
1937
+ "components": {
1938
+ "holding_cost": -3.055,
1939
+ "fairness_penalty": -73.62
1940
+ }
1941
+ },
1942
+ "events": [
1943
+ "no accepted commitments this round"
1944
+ ],
1945
+ "components": {
1946
+ "holding_cost": -3.055,
1947
+ "fairness_penalty": -73.62
1948
+ },
1949
+ "done": true
1950
+ }
1951
+ ]
1952
+ }
scripts/play_subagent_episode.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ ROOT = Path(__file__).resolve().parents[1]
9
+ sys.path.insert(0, str(ROOT / "src"))
10
+
11
+ from supplymind_env.environment import V3SupplyMindEnv
12
+ from supplymind_env.subagent import SUBAGENT_SYSTEM_PROMPT, prompted_subagent_policy
13
+
14
+
15
+ def main() -> None:
16
+ parser = argparse.ArgumentParser(description="Run one prompted SupplyMind subagent episode.")
17
+ parser.add_argument("--task", default="scarcity_negotiation")
18
+ parser.add_argument("--seed", type=int, default=12345)
19
+ parser.add_argument("--out", default=str(ROOT / "results" / "subagent_episode.json"))
20
+ args = parser.parse_args()
21
+
22
+ env = V3SupplyMindEnv(default_task_id=args.task)
23
+ observation = env.reset(args.task, args.seed)
24
+ timeline = []
25
+
26
+ while not env.done:
27
+ action = prompted_subagent_policy(observation)
28
+ result = env.step(action)
29
+ timeline.append(
30
+ {
31
+ "round": observation.round_index,
32
+ "action": action.model_dump(mode="json"),
33
+ "reward": result.reward.model_dump(mode="json"),
34
+ "events": result.observation.feedback.recent_events,
35
+ "components": result.reward.components,
36
+ "done": result.done,
37
+ }
38
+ )
39
+ observation = result.observation
40
+
41
+ payload = {
42
+ "task": args.task,
43
+ "seed": args.seed,
44
+ "system_prompt": SUBAGENT_SYSTEM_PROMPT,
45
+ "episode_summary": env.last_episode_summary,
46
+ "timeline": timeline,
47
+ }
48
+ out = Path(args.out)
49
+ out.parent.mkdir(parents=True, exist_ok=True)
50
+ out.write_text(json.dumps(payload, indent=2), encoding="utf-8")
51
+ print(json.dumps({"out": str(out), "episode_summary": env.last_episode_summary}, indent=2), flush=True)
52
+
53
+
54
+ if __name__ == "__main__":
55
+ main()
src/supplymind_env/api.py CHANGED
@@ -1,11 +1,13 @@
1
  from __future__ import annotations
2
 
 
3
  from fastapi import FastAPI, HTTPException
4
  from fastapi.responses import HTMLResponse
5
 
6
  from .environment import V3SupplyMindEnv
7
  from .models import V3Action
8
  from .policies import heuristic_policy
 
9
  from .task_adapter import PUBLIC_TASK_IDS, is_public_task_id
10
 
11
 
@@ -44,6 +46,27 @@ def create_app() -> FastAPI:
44
  def heuristic_action() -> dict:
45
  return heuristic_policy(env.state()).model_dump(mode="json")
46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  return app
48
 
49
 
 
1
  from __future__ import annotations
2
 
3
+ import json
4
  from fastapi import FastAPI, HTTPException
5
  from fastapi.responses import HTMLResponse
6
 
7
  from .environment import V3SupplyMindEnv
8
  from .models import V3Action
9
  from .policies import heuristic_policy
10
+ from .subagent import SUBAGENT_SYSTEM_PROMPT, build_subagent_prompt, prompted_subagent_policy
11
  from .task_adapter import PUBLIC_TASK_IDS, is_public_task_id
12
 
13
 
 
46
  def heuristic_action() -> dict:
47
  return heuristic_policy(env.state()).model_dump(mode="json")
48
 
49
+ @app.get("/subagent-prompt")
50
+ def subagent_prompt() -> dict:
51
+ observation = env.state()
52
+ return {
53
+ "system_prompt": SUBAGENT_SYSTEM_PROMPT,
54
+ "messages": build_subagent_prompt(observation),
55
+ }
56
+
57
+ @app.get("/subagent-action")
58
+ def subagent_action() -> dict:
59
+ return prompted_subagent_policy(env.state()).model_dump(mode="json")
60
+
61
+ @app.get("/blackbox-trace")
62
+ def blackbox_trace() -> dict:
63
+ from pathlib import Path
64
+
65
+ trace_path = Path(__file__).resolve().parents[2] / "results" / "blackbox_codex_subagent_episode.json"
66
+ if not trace_path.exists():
67
+ raise HTTPException(status_code=404, detail="No black-box subagent trace has been saved yet.")
68
+ return json.loads(trace_path.read_text(encoding="utf-8-sig"))
69
+
70
  return app
71
 
72
 
src/supplymind_env/environment.py CHANGED
@@ -48,6 +48,7 @@ class V3SupplyMindEnv:
48
  self.central_depot_inventory: dict[str, int] = {}
49
  self.depot_trucks_available = 0
50
  self.depot_truck_returns: list[int] = []
 
51
  self.drivers_available: dict[str, int] = {}
52
  self.driver_returns: dict[str, list[int]] = {}
53
  self.trust: dict[str, float] = {}
@@ -104,6 +105,7 @@ class V3SupplyMindEnv:
104
  self.central_depot_inventory = dict(recipe.central_depot_inventory)
105
  self.depot_trucks_available = recipe.profile.depot_trucks
106
  self.depot_truck_returns = []
 
107
  self.drivers_available = dict(recipe.initial_drivers)
108
  self.driver_returns = {warehouse_id: [] for warehouse_id in self.inventory}
109
  self.trust = {spec.warehouse_id: recipe.profile.starting_trust for spec in recipe.warehouse_specs}
@@ -141,6 +143,12 @@ class V3SupplyMindEnv:
141
  trucks_available=self.depot_trucks_available,
142
  trucks_returning=sorted(self.depot_truck_returns),
143
  replenishment_cap=recipe.profile.depot_replenishment_cap,
 
 
 
 
 
 
144
  message=_depot_message(self.central_depot_inventory, self.depot_trucks_available),
145
  ),
146
  warehouses=[
@@ -181,8 +189,8 @@ class V3SupplyMindEnv:
181
  transfer_cap=recipe.profile.transfer_cap,
182
  truck_capacity=recipe.profile.truck_capacity,
183
  objective_brief="Maximize global welfare from compressed warehouse demand reports.",
184
- action_brief="Submit depot replenishments, approved offer matches, and transfer proposals. Warehouses handle local orders.",
185
- episode_brief="Each step resolves central allocation, local warehouse fulfillment, deliveries, and expiries.",
186
  ),
187
  )
188
 
@@ -196,6 +204,7 @@ class V3SupplyMindEnv:
196
  )
197
 
198
  recipe = self._require_recipe()
 
199
  self._return_drivers()
200
  self._return_depot_trucks()
201
  components: dict[str, float] = {}
@@ -208,6 +217,26 @@ class V3SupplyMindEnv:
208
  for signal in generate_market_signals(recipe, self.inventory, self.drivers_available, self.trust)
209
  }
210
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
  moved_units = 0
212
  depot_units = 0
213
  for replenishment in action.central_replenishments:
@@ -406,6 +435,14 @@ class V3SupplyMindEnv:
406
  self.depot_trucks_available += len(returned)
407
  self.depot_truck_returns = [round_index for round_index in self.depot_truck_returns if round_index > self.round_index]
408
 
 
 
 
 
 
 
 
 
409
  def _resolve_local_warehouse_fulfillment(
410
  self,
411
  open_orders: dict[str, OrderTemplate],
@@ -481,6 +518,15 @@ def _depot_message(inventory: dict[str, int], trucks_available: int) -> str:
481
  return "Central depot has limited emergency replenishment capacity."
482
 
483
 
 
 
 
 
 
 
 
 
 
484
  def _matches_priority_policy(order: OrderTemplate, priority_policy: list) -> bool:
485
  for rule in priority_policy:
486
  sku_match = rule.sku is None or rule.sku == order.sku
 
48
  self.central_depot_inventory: dict[str, int] = {}
49
  self.depot_trucks_available = 0
50
  self.depot_truck_returns: list[int] = []
51
+ self.depot_procurement_returns: list[tuple[int, str, int]] = []
52
  self.drivers_available: dict[str, int] = {}
53
  self.driver_returns: dict[str, list[int]] = {}
54
  self.trust: dict[str, float] = {}
 
105
  self.central_depot_inventory = dict(recipe.central_depot_inventory)
106
  self.depot_trucks_available = recipe.profile.depot_trucks
107
  self.depot_truck_returns = []
108
+ self.depot_procurement_returns = []
109
  self.drivers_available = dict(recipe.initial_drivers)
110
  self.driver_returns = {warehouse_id: [] for warehouse_id in self.inventory}
111
  self.trust = {spec.warehouse_id: recipe.profile.starting_trust for spec in recipe.warehouse_specs}
 
143
  trucks_available=self.depot_trucks_available,
144
  trucks_returning=sorted(self.depot_truck_returns),
145
  replenishment_cap=recipe.profile.depot_replenishment_cap,
146
+ procurement_cap=recipe.profile.depot_procurement_cap,
147
+ procurement_lead_time=recipe.profile.depot_procurement_lead_time,
148
+ inbound_procurements=[
149
+ {"arrival_round": round_index, "sku": sku, "units": units}
150
+ for round_index, sku, units in sorted(self.depot_procurement_returns)
151
+ ],
152
  message=_depot_message(self.central_depot_inventory, self.depot_trucks_available),
153
  ),
154
  warehouses=[
 
189
  transfer_cap=recipe.profile.transfer_cap,
190
  truck_capacity=recipe.profile.truck_capacity,
191
  objective_brief="Maximize global welfare from compressed warehouse demand reports.",
192
+ action_brief="Buy future depot stock, ship depot stock, approve offer matches, and propose transfers. Warehouses handle local orders.",
193
+ episode_brief="Each step resolves procurement arrivals, central allocation, local warehouse fulfillment, deliveries, and expiries.",
194
  ),
195
  )
196
 
 
204
  )
205
 
206
  recipe = self._require_recipe()
207
+ self._receive_procurements()
208
  self._return_drivers()
209
  self._return_depot_trucks()
210
  components: dict[str, float] = {}
 
217
  for signal in generate_market_signals(recipe, self.inventory, self.drivers_available, self.trust)
218
  }
219
 
220
+ procured_units = 0
221
+ for procurement in action.central_procurements:
222
+ if procurement.units <= 0 or procurement.sku not in self.central_depot_inventory:
223
+ add_component(components, "invalid_action_penalty", -5.0)
224
+ continue
225
+ if procured_units + procurement.units > recipe.profile.depot_procurement_cap:
226
+ add_component(components, "invalid_action_penalty", -4.0)
227
+ events.append("central procurement cap exceeded")
228
+ continue
229
+ arrival_round = self.round_index + recipe.profile.depot_procurement_lead_time
230
+ unit_cost = _procurement_unit_cost(procurement.sku)
231
+ self.depot_procurement_returns.append((arrival_round, procurement.sku, procurement.units))
232
+ procured_units += procurement.units
233
+ add_component(components, "central_procurement_cost", -unit_cost * procurement.units)
234
+ if self.central_depot_inventory.get(procurement.sku, 0) <= 2:
235
+ add_component(components, "strategic_procurement_bonus", 0.35 * procurement.units)
236
+ events.append(
237
+ f"central bought {procurement.units} {procurement.sku} for depot arrival at round {arrival_round}"
238
+ )
239
+
240
  moved_units = 0
241
  depot_units = 0
242
  for replenishment in action.central_replenishments:
 
435
  self.depot_trucks_available += len(returned)
436
  self.depot_truck_returns = [round_index for round_index in self.depot_truck_returns if round_index > self.round_index]
437
 
438
+ def _receive_procurements(self) -> None:
439
+ arrived = [item for item in self.depot_procurement_returns if item[0] <= self.round_index]
440
+ if not arrived:
441
+ return
442
+ for _, sku, units in arrived:
443
+ self.central_depot_inventory[sku] = self.central_depot_inventory.get(sku, 0) + units
444
+ self.depot_procurement_returns = [item for item in self.depot_procurement_returns if item[0] > self.round_index]
445
+
446
  def _resolve_local_warehouse_fulfillment(
447
  self,
448
  open_orders: dict[str, OrderTemplate],
 
518
  return "Central depot has limited emergency replenishment capacity."
519
 
520
 
521
+ def _procurement_unit_cost(sku: str) -> float:
522
+ return {
523
+ "fresh_milk": 4.0,
524
+ "rice_bag_5kg": 3.2,
525
+ "insulin_pack": 8.0,
526
+ "usb_c_charger": 9.0,
527
+ }.get(sku, 5.0)
528
+
529
+
530
  def _matches_priority_policy(order: OrderTemplate, priority_policy: list) -> bool:
531
  for rule in priority_policy:
532
  sku_match = rule.sku is None or rule.sku == order.sku
src/supplymind_env/generator.py CHANGED
@@ -14,6 +14,8 @@ PROFILES: dict[str, DifficultyProfile] = {
14
  truck_capacity=8,
15
  depot_replenishment_cap=5,
16
  depot_trucks=1,
 
 
17
  starting_trust=0.72,
18
  stockout_penalty_multiplier=0.75,
19
  holding_cost_per_unit=0.04,
@@ -29,6 +31,8 @@ PROFILES: dict[str, DifficultyProfile] = {
29
  truck_capacity=8,
30
  depot_replenishment_cap=6,
31
  depot_trucks=1,
 
 
32
  starting_trust=0.62,
33
  stockout_penalty_multiplier=0.95,
34
  holding_cost_per_unit=0.055,
@@ -44,6 +48,8 @@ PROFILES: dict[str, DifficultyProfile] = {
44
  truck_capacity=10,
45
  depot_replenishment_cap=8,
46
  depot_trucks=2,
 
 
47
  starting_trust=0.55,
48
  stockout_penalty_multiplier=1.05,
49
  holding_cost_per_unit=0.065,
 
14
  truck_capacity=8,
15
  depot_replenishment_cap=5,
16
  depot_trucks=1,
17
+ depot_procurement_cap=5,
18
+ depot_procurement_lead_time=2,
19
  starting_trust=0.72,
20
  stockout_penalty_multiplier=0.75,
21
  holding_cost_per_unit=0.04,
 
31
  truck_capacity=8,
32
  depot_replenishment_cap=6,
33
  depot_trucks=1,
34
+ depot_procurement_cap=6,
35
+ depot_procurement_lead_time=2,
36
  starting_trust=0.62,
37
  stockout_penalty_multiplier=0.95,
38
  holding_cost_per_unit=0.055,
 
48
  truck_capacity=10,
49
  depot_replenishment_cap=8,
50
  depot_trucks=2,
51
+ depot_procurement_cap=8,
52
+ depot_procurement_lead_time=3,
53
  starting_trust=0.55,
54
  stockout_penalty_multiplier=1.05,
55
  holding_cost_per_unit=0.065,
src/supplymind_env/models.py CHANGED
@@ -21,6 +21,8 @@ class DifficultyProfile(BaseModel):
21
  truck_capacity: int
22
  depot_replenishment_cap: int = 0
23
  depot_trucks: int = 1
 
 
24
  starting_trust: float
25
  stockout_penalty_multiplier: float
26
  holding_cost_per_unit: float
@@ -88,6 +90,9 @@ class CentralDepotSnapshot(BaseModel):
88
  trucks_available: int
89
  trucks_returning: list[int] = Field(default_factory=list)
90
  replenishment_cap: int
 
 
 
91
  message: str = ""
92
 
93
 
@@ -153,6 +158,13 @@ class CentralReplenishmentProposal(BaseModel):
153
  units: int
154
 
155
 
 
 
 
 
 
 
 
156
  class MarketSignal(BaseModel):
157
  model_config = ConfigDict(frozen=True)
158
 
@@ -195,6 +207,7 @@ class CoalitionDeal(BaseModel):
195
 
196
  class V3Action(BaseModel):
197
  fulfillments: list[FulfillmentDecision] = Field(default_factory=list)
 
198
  central_replenishments: list[CentralReplenishmentProposal] = Field(default_factory=list)
199
  inventory_transfers: list[InventoryTransferProposal] = Field(default_factory=list)
200
  driver_loans: list[DriverLoanProposal] = Field(default_factory=list)
 
21
  truck_capacity: int
22
  depot_replenishment_cap: int = 0
23
  depot_trucks: int = 1
24
+ depot_procurement_cap: int = 0
25
+ depot_procurement_lead_time: int = 2
26
  starting_trust: float
27
  stockout_penalty_multiplier: float
28
  holding_cost_per_unit: float
 
90
  trucks_available: int
91
  trucks_returning: list[int] = Field(default_factory=list)
92
  replenishment_cap: int
93
+ procurement_cap: int = 0
94
+ procurement_lead_time: int = 0
95
+ inbound_procurements: list[dict[str, int | str]] = Field(default_factory=list)
96
  message: str = ""
97
 
98
 
 
158
  units: int
159
 
160
 
161
+ class CentralProcurementProposal(BaseModel):
162
+ model_config = ConfigDict(frozen=True)
163
+
164
+ sku: SKU
165
+ units: int
166
+
167
+
168
  class MarketSignal(BaseModel):
169
  model_config = ConfigDict(frozen=True)
170
 
 
207
 
208
  class V3Action(BaseModel):
209
  fulfillments: list[FulfillmentDecision] = Field(default_factory=list)
210
+ central_procurements: list[CentralProcurementProposal] = Field(default_factory=list)
211
  central_replenishments: list[CentralReplenishmentProposal] = Field(default_factory=list)
212
  inventory_transfers: list[InventoryTransferProposal] = Field(default_factory=list)
213
  driver_loans: list[DriverLoanProposal] = Field(default_factory=list)
src/supplymind_env/policies.py CHANGED
@@ -23,6 +23,7 @@ def baseline_policy(observation: V3Observation) -> V3Action:
23
 
24
  def heuristic_policy(observation: V3Observation) -> V3Action:
25
  central_replenishments = list(baseline_policy(observation).central_replenishments)
 
26
  offer_matches = []
27
 
28
  offers = [signal for signal in observation.market_signals if signal.signal_type == "inventory_offer"]
@@ -31,6 +32,10 @@ def heuristic_policy(observation: V3Observation) -> V3Action:
31
  (report.warehouse_id, report.sku): report
32
  for report in observation.demand_reports
33
  }
 
 
 
 
34
  used_offers: set[str] = set()
35
  used_requests: set[str] = set()
36
  for request in sorted(requests, key=lambda signal: (-signal.urgency, -signal.units)):
@@ -59,22 +64,38 @@ def heuristic_policy(observation: V3Observation) -> V3Action:
59
 
60
  used_trucks = 0
61
  committed_depot: dict[str, int] = {}
 
62
  matched_requests = {match["request_signal_id"] for match in offer_matches}
63
  for report in sorted(observation.demand_reports, key=lambda item: (-item.urgency, -item.missed_units_last_round, -item.at_risk_units, -item.forecast_units)):
64
- if used_trucks >= observation.central_depot.trucks_available:
65
- break
66
- if f"{report.warehouse_id}:request:{report.sku}" in matched_requests:
67
- continue
68
  available = _warehouse_inventory(observation, report.warehouse_id, report.sku)
69
- pressure = max(0, report.requested_units + report.at_risk_units + report.missed_units_last_round - available)
70
- depot_left = observation.central_depot.inventory.get(report.sku, 0) - committed_depot.get(report.sku, 0)
71
- units = min(pressure, depot_left, 2)
72
- if units > 0 and (report.urgency >= 3 or report.missed_units_last_round > 0):
73
- central_replenishments.append({"to_warehouse": report.warehouse_id, "sku": report.sku, "units": units})
74
- committed_depot[report.sku] = committed_depot.get(report.sku, 0) + units
75
- used_trucks += 1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
77
  return V3Action(
 
78
  central_replenishments=central_replenishments[: observation.central_depot.trucks_available],
79
  offer_matches=offer_matches[:3],
80
  )
 
23
 
24
  def heuristic_policy(observation: V3Observation) -> V3Action:
25
  central_replenishments = list(baseline_policy(observation).central_replenishments)
26
+ central_procurements = []
27
  offer_matches = []
28
 
29
  offers = [signal for signal in observation.market_signals if signal.signal_type == "inventory_offer"]
 
32
  (report.warehouse_id, report.sku): report
33
  for report in observation.demand_reports
34
  }
35
+ inbound_by_sku: dict[str, int] = {}
36
+ for item in observation.central_depot.inbound_procurements:
37
+ sku = str(item.get("sku", ""))
38
+ inbound_by_sku[sku] = inbound_by_sku.get(sku, 0) + int(item.get("units", 0))
39
  used_offers: set[str] = set()
40
  used_requests: set[str] = set()
41
  for request in sorted(requests, key=lambda signal: (-signal.urgency, -signal.units)):
 
64
 
65
  used_trucks = 0
66
  committed_depot: dict[str, int] = {}
67
+ procurement_by_sku: dict[str, int] = {}
68
  matched_requests = {match["request_signal_id"] for match in offer_matches}
69
  for report in sorted(observation.demand_reports, key=lambda item: (-item.urgency, -item.missed_units_last_round, -item.at_risk_units, -item.forecast_units)):
 
 
 
 
70
  available = _warehouse_inventory(observation, report.warehouse_id, report.sku)
71
+ if used_trucks < observation.central_depot.trucks_available and f"{report.warehouse_id}:request:{report.sku}" not in matched_requests:
72
+ pressure = max(0, report.requested_units + report.at_risk_units + report.missed_units_last_round - available)
73
+ depot_left = observation.central_depot.inventory.get(report.sku, 0) - committed_depot.get(report.sku, 0)
74
+ units = min(pressure, depot_left, 2)
75
+ if units > 0 and (report.urgency >= 3 or report.missed_units_last_round > 0):
76
+ central_replenishments.append({"to_warehouse": report.warehouse_id, "sku": report.sku, "units": units})
77
+ committed_depot[report.sku] = committed_depot.get(report.sku, 0) + units
78
+ used_trucks += 1
79
+
80
+ projected_pressure = report.requested_units + report.at_risk_units + report.forecast_units + report.missed_units_last_round
81
+ depot_left_after_shipments = (
82
+ observation.central_depot.inventory.get(report.sku, 0)
83
+ + inbound_by_sku.get(report.sku, 0)
84
+ + procurement_by_sku.get(report.sku, 0)
85
+ - committed_depot.get(report.sku, 0)
86
+ )
87
+ enough_time_to_use_purchase = observation.remaining_rounds > observation.central_depot.procurement_lead_time + 2
88
+ if enough_time_to_use_purchase and report.urgency >= 2 and projected_pressure >= 5 and depot_left_after_shipments <= 1:
89
+ already = procurement_by_sku.get(report.sku, 0)
90
+ units_to_buy = min(2, projected_pressure - depot_left_after_shipments, observation.central_depot.procurement_cap - sum(procurement_by_sku.values()))
91
+ if units_to_buy > 0:
92
+ procurement_by_sku[report.sku] = already + units_to_buy
93
+
94
+ for sku, units in procurement_by_sku.items():
95
+ central_procurements.append({"sku": sku, "units": units})
96
 
97
  return V3Action(
98
+ central_procurements=central_procurements,
99
  central_replenishments=central_replenishments[: observation.central_depot.trucks_available],
100
  offer_matches=offer_matches[:3],
101
  )
src/supplymind_env/solver.py CHANGED
@@ -7,7 +7,7 @@ from .policies import baseline_policy, heuristic_policy
7
 
8
 
9
  def privileged_reference_policy(observation: V3Observation) -> V3Action:
10
- action = baseline_policy(observation)
11
  priority_policy = []
12
  if observation.demand_reports:
13
  top_report = max(
@@ -44,6 +44,7 @@ def privileged_reference_policy(observation: V3Observation) -> V3Action:
44
  )
45
  break
46
  return V3Action(
 
47
  central_replenishments=action.central_replenishments,
48
  inventory_transfers=transfers[:2],
49
  driver_loans=action.driver_loans,
@@ -84,6 +85,7 @@ def _oracle_action(env: V3SupplyMindEnv, observation: V3Observation) -> V3Action
84
  recipe = env._require_recipe()
85
  specs_by_region = {spec.region: spec for spec in recipe.warehouse_specs}
86
  replenishments = []
 
87
  committed_depot: dict[str, int] = {}
88
  used_trucks = 0
89
  for order in sorted(
@@ -104,4 +106,12 @@ def _oracle_action(env: V3SupplyMindEnv, observation: V3Observation) -> V3Action
104
  replenishments.append({"to_warehouse": spec.warehouse_id, "sku": order.sku, "units": units})
105
  committed_depot[order.sku] = committed_depot.get(order.sku, 0) + units
106
  used_trucks += 1
107
- return V3Action(central_replenishments=replenishments)
 
 
 
 
 
 
 
 
 
7
 
8
 
9
  def privileged_reference_policy(observation: V3Observation) -> V3Action:
10
+ action = heuristic_policy(observation)
11
  priority_policy = []
12
  if observation.demand_reports:
13
  top_report = max(
 
44
  )
45
  break
46
  return V3Action(
47
+ central_procurements=action.central_procurements,
48
  central_replenishments=action.central_replenishments,
49
  inventory_transfers=transfers[:2],
50
  driver_loans=action.driver_loans,
 
85
  recipe = env._require_recipe()
86
  specs_by_region = {spec.region: spec for spec in recipe.warehouse_specs}
87
  replenishments = []
88
+ procurements_by_sku: dict[str, int] = {}
89
  committed_depot: dict[str, int] = {}
90
  used_trucks = 0
91
  for order in sorted(
 
106
  replenishments.append({"to_warehouse": spec.warehouse_id, "sku": order.sku, "units": units})
107
  committed_depot[order.sku] = committed_depot.get(order.sku, 0) + units
108
  used_trucks += 1
109
+ if depot_left <= 2 and env.round_index + recipe.profile.depot_procurement_lead_time < recipe.profile.total_rounds:
110
+ already = sum(procurements_by_sku.values())
111
+ buy_units = min(3, recipe.profile.depot_procurement_cap - already)
112
+ if buy_units > 0:
113
+ procurements_by_sku[order.sku] = procurements_by_sku.get(order.sku, 0) + buy_units
114
+ return V3Action(
115
+ central_procurements=[{"sku": sku, "units": units} for sku, units in procurements_by_sku.items()],
116
+ central_replenishments=replenishments,
117
+ )
src/supplymind_env/subagent.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import json
4
+
5
+ from .models import V3Action, V3Observation
6
+ from .policies import heuristic_policy
7
+
8
+
9
+ SUBAGENT_SYSTEM_PROMPT = """You are a small central-planning subagent playing SupplyMind.
10
+ You do not see raw customer orders. You only see warehouse reports, depot stock, route costs, market signals, and reward feedback.
11
+
12
+ Goal:
13
+ Maximize global network welfare over the full episode, not just this round.
14
+
15
+ Action JSON schema:
16
+ {
17
+ "central_procurements": [{"sku": "fresh_milk", "units": 2}],
18
+ "central_replenishments": [{"to_warehouse": "north", "sku": "insulin_pack", "units": 2}],
19
+ "offer_matches": [{"offer_signal_id": "west:offer:fresh_milk", "request_signal_id": "north:request:fresh_milk", "units": 2, "compensation": 12.0}],
20
+ "inventory_transfers": [{"from_warehouse": "west", "to_warehouse": "north", "sku": "fresh_milk", "units": 2, "compensation": 12.0}],
21
+ "priority_policy": [],
22
+ "defer_orders": [],
23
+ "coalition_deals": []
24
+ }
25
+
26
+ Policy:
27
+ 1. Ship depot stock to urgent warehouses when trucks and depot inventory are available.
28
+ 2. Buy into central depot when repeated forecast pressure is high and depot stock is low; purchases arrive after lead time.
29
+ 3. Prefer offer_matches over direct transfers when public offers and requests already exist.
30
+ 4. Do not overbuy late in the episode.
31
+ 5. Avoid transfers that look unlikely to satisfy the source warehouse's local incentive.
32
+ Return JSON only."""
33
+
34
+
35
+ def build_subagent_prompt(observation: V3Observation) -> list[dict[str, str]]:
36
+ return [
37
+ {"role": "system", "content": SUBAGENT_SYSTEM_PROMPT},
38
+ {
39
+ "role": "user",
40
+ "content": json.dumps(observation.model_dump(mode="json"), separators=(",", ":")),
41
+ },
42
+ ]
43
+
44
+
45
+ def prompted_subagent_policy(observation: V3Observation) -> V3Action:
46
+ """A local stand-in for the small prompted model, useful when no API token is set."""
47
+ return heuristic_policy(observation)
48
+
49
+
50
+ __all__ = ["SUBAGENT_SYSTEM_PROMPT", "build_subagent_prompt", "prompted_subagent_policy"]
static/index.html CHANGED
@@ -82,8 +82,11 @@
82
  <input id="seed" type="number" value="12345" />
83
  <button id="reset">Reset</button>
84
  <button id="heuristic" class="secondary">Load Heuristic</button>
 
85
  <button id="step">Step</button>
86
- <button id="run" class="secondary">Run Episode</button>
 
 
87
  </div>
88
  </header>
89
  <main>
@@ -120,7 +123,11 @@
120
  </section>
121
  <section>
122
  <h2>Action JSON</h2>
123
- <textarea id="action">{"central_replenishments":[],"inventory_transfers":[],"offer_matches":[],"priority_policy":[],"defer_orders":[],"coalition_deals":[]}</textarea>
 
 
 
 
124
  </section>
125
  <section>
126
  <h2>Events</h2>
@@ -160,8 +167,43 @@
160
  $("action").value = JSON.stringify(await res.json(), null, 2);
161
  }
162
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  function emptyAction() {
164
  return {
 
165
  central_replenishments: [],
166
  inventory_transfers: [],
167
  offer_matches: [],
@@ -198,18 +240,24 @@
198
  return data.done;
199
  }
200
 
201
- async function runEpisode() {
202
  if (running) return;
203
  running = true;
204
  setBusy(true);
205
  try {
206
- await loadHeuristic();
 
207
  let done = false;
208
  let guard = 0;
209
- while (!done && guard < 20) {
 
210
  done = await step();
211
  guard += 1;
212
  await new Promise(resolve => setTimeout(resolve, 160));
 
 
 
 
213
  }
214
  } finally {
215
  running = false;
@@ -220,8 +268,11 @@
220
  function setBusy(value) {
221
  $("reset").disabled = value;
222
  $("heuristic").disabled = value;
 
223
  $("step").disabled = value;
224
  $("run").disabled = value;
 
 
225
  }
226
 
227
  function render(lastStep) {
@@ -235,7 +286,9 @@
235
  <div class="barrow"><span>${sku}</span><div class="bar"><span style="width:${Math.min(100, units * 10)}%"></span></div><span>${units}</span></div>
236
  `).join("")}
237
  </div>
238
- <p class="muted">Returning trucks [${state.central_depot.trucks_returning.join(", ")}], cap ${state.central_depot.replenishment_cap}</p>
 
 
239
  </div>`;
240
  $("warehouses").innerHTML = state.warehouses.map(w => `
241
  <div class="card">
@@ -292,6 +345,7 @@
292
  function decisionChips(action) {
293
  const current = action || emptyAction();
294
  const chips = [
 
295
  ["depot", current.central_replenishments?.length || 0],
296
  ["transfers", current.inventory_transfers?.length || 0],
297
  ["matches", current.offer_matches?.length || 0],
@@ -319,11 +373,19 @@
319
  return `Routes: nearest ${near[0]} ${Number(near[1]).toFixed(1)}, farthest ${far[0]} ${Number(far[1]).toFixed(1)}`;
320
  }
321
 
 
 
 
 
 
322
  $("reset").onclick = reset;
323
  $("heuristic").onclick = loadHeuristic;
 
324
  $("step").onclick = step;
325
- $("run").onclick = runEpisode;
326
- reset().then(loadHeuristic);
 
 
327
  </script>
328
  </body>
329
  </html>
 
82
  <input id="seed" type="number" value="12345" />
83
  <button id="reset">Reset</button>
84
  <button id="heuristic" class="secondary">Load Heuristic</button>
85
+ <button id="subagent" class="secondary">Load Subagent</button>
86
  <button id="step">Step</button>
87
+ <button id="run" class="secondary">Run Heuristic</button>
88
+ <button id="run-subagent" class="secondary">Run Subagent</button>
89
+ <button id="load-trace" class="ghost">Load Black-box Trace</button>
90
  </div>
91
  </header>
92
  <main>
 
123
  </section>
124
  <section>
125
  <h2>Action JSON</h2>
126
+ <textarea id="action">{"central_procurements":[],"central_replenishments":[],"inventory_transfers":[],"offer_matches":[],"priority_policy":[],"defer_orders":[],"coalition_deals":[]}</textarea>
127
+ </section>
128
+ <section>
129
+ <h2>Subagent Prompt</h2>
130
+ <pre id="prompt">Prompt not loaded yet.</pre>
131
  </section>
132
  <section>
133
  <h2>Events</h2>
 
167
  $("action").value = JSON.stringify(await res.json(), null, 2);
168
  }
169
 
170
+ async function loadSubagent() {
171
+ const [actionRes, promptRes] = await Promise.all([
172
+ fetch("/subagent-action"),
173
+ fetch("/subagent-prompt")
174
+ ]);
175
+ $("action").value = JSON.stringify(await actionRes.json(), null, 2);
176
+ const prompt = await promptRes.json();
177
+ $("prompt").textContent = prompt.system_prompt;
178
+ }
179
+
180
+ async function loadBlackboxTrace() {
181
+ const res = await fetch("/blackbox-trace");
182
+ if (!res.ok) {
183
+ alert("No black-box trace found yet.");
184
+ return;
185
+ }
186
+ const trace = await res.json();
187
+ episode = (trace.rounds || []).map(round => ({
188
+ round: round.round_index,
189
+ reward: round.reward,
190
+ cumulative: round.cumulative_reward,
191
+ decision: round.action,
192
+ events: [
193
+ ...(round.reasoning ? [`reasoning: ${round.reasoning}`] : []),
194
+ ...(round.events || [])
195
+ ],
196
+ components: round.components,
197
+ reports: round.observation_summary?.demand_reports?.length || 0,
198
+ done: round.done
199
+ }));
200
+ $("prompt").textContent = `Black-box Codex subagent replay\nTask: ${trace.task}\nSeed: ${trace.seed}\nTotal reward: ${trace.final_episode_summary?.total_reward ?? "unknown"}\nGraded score: ${trace.final_episode_summary?.graded_score ?? "not returned"}`;
201
+ render();
202
+ }
203
+
204
  function emptyAction() {
205
  return {
206
+ central_procurements: [],
207
  central_replenishments: [],
208
  inventory_transfers: [],
209
  offer_matches: [],
 
240
  return data.done;
241
  }
242
 
243
+ async function runEpisode(mode = "heuristic") {
244
  if (running) return;
245
  running = true;
246
  setBusy(true);
247
  try {
248
+ if (mode === "subagent") await loadSubagent();
249
+ else await loadHeuristic();
250
  let done = false;
251
  let guard = 0;
252
+ const maxSteps = Math.max(5, state?.scenario_info?.total_rounds || 40);
253
+ while (!done && guard < maxSteps) {
254
  done = await step();
255
  guard += 1;
256
  await new Promise(resolve => setTimeout(resolve, 160));
257
+ if (!done) {
258
+ if (mode === "subagent") await loadSubagent();
259
+ else await loadHeuristic();
260
+ }
261
  }
262
  } finally {
263
  running = false;
 
268
  function setBusy(value) {
269
  $("reset").disabled = value;
270
  $("heuristic").disabled = value;
271
+ $("subagent").disabled = value;
272
  $("step").disabled = value;
273
  $("run").disabled = value;
274
+ $("run-subagent").disabled = value;
275
+ $("load-trace").disabled = value;
276
  }
277
 
278
  function render(lastStep) {
 
286
  <div class="barrow"><span>${sku}</span><div class="bar"><span style="width:${Math.min(100, units * 10)}%"></span></div><span>${units}</span></div>
287
  `).join("")}
288
  </div>
289
+ <p class="muted">Returning trucks [${state.central_depot.trucks_returning.join(", ")}], ship cap ${state.central_depot.replenishment_cap}</p>
290
+ <p class="muted">Buy cap ${state.central_depot.procurement_cap}, lead ${state.central_depot.procurement_lead_time} round(s)</p>
291
+ <p class="muted">${procurementSummary(state.central_depot.inbound_procurements)}</p>
292
  </div>`;
293
  $("warehouses").innerHTML = state.warehouses.map(w => `
294
  <div class="card">
 
345
  function decisionChips(action) {
346
  const current = action || emptyAction();
347
  const chips = [
348
+ ["buy", current.central_procurements?.length || 0],
349
  ["depot", current.central_replenishments?.length || 0],
350
  ["transfers", current.inventory_transfers?.length || 0],
351
  ["matches", current.offer_matches?.length || 0],
 
373
  return `Routes: nearest ${near[0]} ${Number(near[1]).toFixed(1)}, farthest ${far[0]} ${Number(far[1]).toFixed(1)}`;
374
  }
375
 
376
+ function procurementSummary(inbound) {
377
+ if (!inbound || !inbound.length) return "No inbound depot purchases.";
378
+ return `Inbound purchases: ${inbound.map(item => `${item.units} ${item.sku} @ round ${item.arrival_round}`).join(", ")}`;
379
+ }
380
+
381
  $("reset").onclick = reset;
382
  $("heuristic").onclick = loadHeuristic;
383
+ $("subagent").onclick = loadSubagent;
384
  $("step").onclick = step;
385
+ $("run").onclick = () => runEpisode("heuristic");
386
+ $("run-subagent").onclick = () => runEpisode("subagent");
387
+ $("load-trace").onclick = loadBlackboxTrace;
388
+ reset().then(loadSubagent);
389
  </script>
390
  </body>
391
  </html>