@agentshouse/mdruntime 0.1.0-alpha.42 → 0.1.0-alpha.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/AGENTS.md +22 -11
  2. package/dist/adapter.d.ts +23 -1
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/adapter.js.map +1 -1
  5. package/dist/bootstrap.d.ts.map +1 -1
  6. package/dist/bootstrap.js +6 -1
  7. package/dist/bootstrap.js.map +1 -1
  8. package/dist/change-set.d.ts.map +1 -1
  9. package/dist/change-set.js +3 -2
  10. package/dist/change-set.js.map +1 -1
  11. package/dist/client.d.ts +1 -0
  12. package/dist/client.d.ts.map +1 -1
  13. package/dist/client.js +4 -0
  14. package/dist/client.js.map +1 -1
  15. package/dist/connection.d.ts +1 -0
  16. package/dist/connection.d.ts.map +1 -1
  17. package/dist/connection.js +86 -31
  18. package/dist/connection.js.map +1 -1
  19. package/dist/host.d.ts.map +1 -1
  20. package/dist/host.js +2 -0
  21. package/dist/host.js.map +1 -1
  22. package/dist/index.d.ts +1 -1
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/memory.d.ts +2 -1
  26. package/dist/memory.d.ts.map +1 -1
  27. package/dist/memory.js +53 -10
  28. package/dist/memory.js.map +1 -1
  29. package/dist/overlay.d.ts +7 -2
  30. package/dist/overlay.d.ts.map +1 -1
  31. package/dist/overlay.js +48 -15
  32. package/dist/overlay.js.map +1 -1
  33. package/dist/query.d.ts +4 -0
  34. package/dist/query.d.ts.map +1 -1
  35. package/dist/query.js +4 -1
  36. package/dist/query.js.map +1 -1
  37. package/dist/read-side.d.ts.map +1 -1
  38. package/dist/read-side.js +6 -0
  39. package/dist/read-side.js.map +1 -1
  40. package/dist/refresh.d.ts +3 -3
  41. package/dist/refresh.d.ts.map +1 -1
  42. package/dist/refresh.js +20 -4
  43. package/dist/refresh.js.map +1 -1
  44. package/dist/replica.d.ts.map +1 -1
  45. package/dist/replica.js +9 -0
  46. package/dist/replica.js.map +1 -1
  47. package/dist/rows.d.ts +3 -1
  48. package/dist/rows.d.ts.map +1 -1
  49. package/dist/rows.js +5 -3
  50. package/dist/rows.js.map +1 -1
  51. package/dist/store.d.ts +2 -1
  52. package/dist/store.d.ts.map +1 -1
  53. package/dist/store.js +20 -12
  54. package/dist/store.js.map +1 -1
  55. package/dist/wire.d.ts +1 -1
  56. package/dist/wire.d.ts.map +1 -1
  57. package/dist/wire.js +1 -0
  58. package/dist/wire.js.map +1 -1
  59. package/package.json +1 -1
@@ -57,6 +57,7 @@ export function composeRuntime(options) {
57
57
  const presentations = new Map();
58
58
  const outcomes = new Map();
59
59
  const outcomeRooms = new Map();
60
+ const wanted = new Map();
60
61
  let limits = [];
61
62
  let slots = [];
62
63
  let capabilities = [];
@@ -449,6 +450,7 @@ export function composeRuntime(options) {
449
450
  for (const locator of listedLocators)scopedRefusals.delete(locator);
450
451
  discovered.clear();
451
452
  for (const room of listed)discovered.set(room.locator, room);
453
+ for (const locator of wanted.keys())if (!listedLocators.has(locator)) wanted.delete(locator);
452
454
  await dropUnlisted(listedLocators, local);
453
455
  for (const room of listed){
454
456
  const held = replicas.get(room.locator)?.confirmed.record;
@@ -751,11 +753,19 @@ export function composeRuntime(options) {
751
753
  }, prior?.confirmed);
752
754
  if (retained.kind !== 'staged') throw new Error(`Cannot retype staged Room ${room.locator}`);
753
755
  const queue = prior?.queue ?? [];
754
- const accepted = queue.filter((batch)=>outcomes.get(batch.id)?.kind === 'accepted');
756
+ const roomVersion = retained.confirmed.record.roomVersion;
757
+ const accepted = queue.filter((batch)=>{
758
+ const outcome = outcomes.get(batch.id);
759
+ return outcome?.kind === 'accepted' && options.adapter.reached(room.locator, roomVersion, outcome.roomVersion);
760
+ });
755
761
  const set = await settle(local, room.locator, prior, retained.confirmed, queue.filter((batch)=>!accepted.includes(batch)), {
756
762
  room: true
757
763
  });
758
764
  for (const batch of accepted)pendings.delete(batch.id);
765
+ const target = wanted.get(room.locator);
766
+ if (target !== undefined && options.adapter.reached(room.locator, roomVersion, target)) {
767
+ wanted.delete(room.locator);
768
+ }
759
769
  unreadable.delete(room.locator);
760
770
  sourceRefusals.delete(room.locator);
761
771
  declarationRefusals.delete(room.locator);
@@ -978,6 +988,7 @@ export function composeRuntime(options) {
978
988
  name,
979
989
  input
980
990
  });
991
+ if (result.kind === 'action' && result.at !== undefined) want(result.at);
981
992
  if (result.kind === 'scoped-refusal') {
982
993
  const room = replicas.get(result.locator)?.confirmed.record;
983
994
  if (room !== undefined) await scoped(result, room, await openLocal());
@@ -996,10 +1007,36 @@ export function composeRuntime(options) {
996
1007
  function continuing() {
997
1008
  return !closed && !discoveryPaused;
998
1009
  }
999
- async function pullRefresh(authorized, confirmed) {
1010
+ function reachedBy(locator, roomVersion) {
1011
+ const held = replicas.get(locator);
1012
+ return held !== undefined && options.adapter.reached(locator, held.confirmed.record.roomVersion, roomVersion);
1013
+ }
1014
+ function want({ locator, roomVersion }) {
1015
+ if (reachedBy(locator, roomVersion)) return;
1016
+ const held = wanted.get(locator);
1017
+ if (held === undefined || options.adapter.reached(locator, roomVersion, held)) {
1018
+ wanted.set(locator, roomVersion);
1019
+ }
1020
+ }
1021
+ function reachOf(locator) {
1022
+ let target = wanted.get(locator);
1023
+ const versions = (replicas.get(locator)?.queue ?? []).flatMap((batch)=>{
1024
+ const outcome = outcomes.get(batch.id);
1025
+ return outcome?.kind === 'accepted' ? [
1026
+ outcome.roomVersion
1027
+ ] : [];
1028
+ });
1029
+ for (const version of versions){
1030
+ if (target === undefined || options.adapter.reached(locator, version, target)) {
1031
+ target = version;
1032
+ }
1033
+ }
1034
+ return target === undefined || reachedBy(locator, target) ? undefined : target;
1035
+ }
1036
+ async function pullRefresh(authorized, confirmed, reach) {
1000
1037
  if (!continuing()) return unconfirmed;
1001
1038
  try {
1002
- const result = await refreshRoom(options.adapter, authorized, confirmed, continuing);
1039
+ const result = await refreshRoom(options.adapter, authorized, confirmed, continuing, reach);
1003
1040
  const detail = result.kind === 'advanced' ? result.confirmed.record.roomVersion : result.kind;
1004
1041
  journal.record(`transfer refresh ${confirmed.record.locator} ${detail}`);
1005
1042
  return result;
@@ -1026,7 +1063,7 @@ export function composeRuntime(options) {
1026
1063
  async function advance(room, local, authorized) {
1027
1064
  const held = replicas.get(room.locator);
1028
1065
  if (held !== undefined) {
1029
- const refreshed = await pullRefresh(authorized, held.confirmed);
1066
+ const refreshed = await pullRefresh(authorized, held.confirmed, reachOf(room.locator));
1030
1067
  if (!continuing()) return unconfirmed;
1031
1068
  if (refreshed.kind === 'still-current') {
1032
1069
  if (sourceRefusals.has(room.locator)) return unconfirmed;
@@ -1054,6 +1091,8 @@ export function composeRuntime(options) {
1054
1091
  await scoped(withheld, room, local);
1055
1092
  } else if (withheld.kind === 'transport-uncertainty') {
1056
1093
  progress.reachable = false;
1094
+ } else if (withheld.kind === 'retryable-refusal') {
1095
+ journal.record(`refusal ${withheld.kind} ${withheld.code}`);
1057
1096
  } else if (withheld.kind === 'room-not-readable') {
1058
1097
  unreadable.add(room.locator);
1059
1098
  list(room, false);
@@ -1145,7 +1184,7 @@ export function composeRuntime(options) {
1145
1184
  function logAccepted(locator, submitted, accepted) {
1146
1185
  journal.record(`outcome ${locator} ${submitted.id} accepted ${accepted.roomVersion}` + (accepted.author === undefined ? '' : ` author ${accepted.author}`) + (accepted.time === undefined ? '' : ` time ${accepted.time}`));
1147
1186
  }
1148
- async function holdAccepted(room, local, submitted, accepted, refused) {
1187
+ async function recordAccepted(room, local, submitted, accepted) {
1149
1188
  await exclusive(async ()=>{
1150
1189
  if (!continuing()) return;
1151
1190
  const current = replicas.get(room.locator);
@@ -1169,7 +1208,6 @@ export function composeRuntime(options) {
1169
1208
  outcomeRooms.set(submitted.id, room.locator);
1170
1209
  logAccepted(room.locator, submitted, accepted);
1171
1210
  });
1172
- if (refused !== null && continuing()) refusedSource(room, refused);
1173
1211
  }
1174
1212
  async function commitAccept(room, local, submitted, accepted, base, overlay) {
1175
1213
  if (!continuing()) return unconfirmed;
@@ -1201,13 +1239,20 @@ export function composeRuntime(options) {
1201
1239
  ...status,
1202
1240
  ...attention()
1203
1241
  });
1204
- logAccepted(room.locator, submitted, accepted);
1205
1242
  return null;
1206
1243
  }
1244
+ async function accepting(room, local, submitted, accepted, pulled, fresh) {
1245
+ const roomVersion = pulled.record.roomVersion;
1246
+ if (options.adapter.reached(room.locator, roomVersion, accepted.roomVersion)) {
1247
+ return committed(room, local, submitted, accepted, pulled, roomVersion === accepted.roomVersion);
1248
+ }
1249
+ if (fresh && continuing()) await publish(local, room, pulled);
1250
+ return false;
1251
+ }
1207
1252
  async function committed(room, local, submitted, accepted, base, overlay) {
1208
1253
  const failed = await exclusive(()=>commitAccept(room, local, submitted, accepted, base, overlay));
1209
1254
  if (failed === null) return true;
1210
- await holdAccepted(room, local, submitted, accepted, failed.kind === 'refused' ? failed : null);
1255
+ if (failed.kind === 'refused' && continuing()) refusedSource(room, failed);
1211
1256
  return false;
1212
1257
  }
1213
1258
  async function submitRoom(room, local, authorized, progress) {
@@ -1338,9 +1383,10 @@ export function composeRuntime(options) {
1338
1383
  if (withheld !== null) return withhold(withheld, room, local, progress);
1339
1384
  continue;
1340
1385
  }
1386
+ await recordAccepted(room, local, head, result);
1341
1387
  const from = replicas.get(room.locator)?.confirmed;
1342
1388
  if (from === undefined) return;
1343
- const pulled = await pullRefresh(authorized, from);
1389
+ const pulled = await pullRefresh(authorized, from, reachOf(room.locator));
1344
1390
  if (!continuing()) return;
1345
1391
  if (pulled.kind === 'revoked-authorization') {
1346
1392
  await refuse('revoked-authorization');
@@ -1351,16 +1397,9 @@ export function composeRuntime(options) {
1351
1397
  progress.complete = false;
1352
1398
  return;
1353
1399
  }
1354
- if (pulled.kind === 'still-current') {
1355
- if (!await committed(room, local, head, result, from, true)) {
1356
- progress.complete = false;
1357
- return;
1358
- }
1359
- continue;
1360
- }
1361
- if (pulled.kind === 'advanced') {
1362
- const overlay = pulled.confirmed.record.roomVersion === result.roomVersion;
1363
- if (!await committed(room, local, head, result, pulled.confirmed, overlay)) {
1400
+ if (pulled.kind === 'still-current' || pulled.kind === 'advanced') {
1401
+ const fresh = pulled.kind === 'advanced';
1402
+ if (!await accepting(room, local, head, result, fresh ? pulled.confirmed : from, fresh)) {
1364
1403
  progress.complete = false;
1365
1404
  return;
1366
1405
  }
@@ -1379,8 +1418,7 @@ export function composeRuntime(options) {
1379
1418
  return;
1380
1419
  }
1381
1420
  if (bootstrapped.kind === 'staged') {
1382
- const overlay = bootstrapped.confirmed.record.roomVersion === result.roomVersion;
1383
- if (!await committed(room, local, head, result, bootstrapped.confirmed, overlay)) {
1421
+ if (!await accepting(room, local, head, result, bootstrapped.confirmed, true)) {
1384
1422
  progress.complete = false;
1385
1423
  return;
1386
1424
  }
@@ -1394,7 +1432,7 @@ export function composeRuntime(options) {
1394
1432
  list(room, false);
1395
1433
  emitRooms();
1396
1434
  } else if (bootstrapped.kind === 'refused') {
1397
- await holdAccepted(room, local, head, result, bootstrapped);
1435
+ refusedSource(room, bootstrapped);
1398
1436
  }
1399
1437
  return;
1400
1438
  }
@@ -1405,8 +1443,10 @@ export function composeRuntime(options) {
1405
1443
  unreadable.add(room.locator);
1406
1444
  list(room, false);
1407
1445
  emitRooms();
1446
+ } else if (pulled.kind === 'retryable-refusal') {
1447
+ journal.record(`refusal ${pulled.kind} ${pulled.code}`);
1408
1448
  } else if (pulled.kind === 'refused') {
1409
- await holdAccepted(room, local, head, result, pulled);
1449
+ refusedSource(room, pulled);
1410
1450
  }
1411
1451
  return;
1412
1452
  }
@@ -1589,14 +1629,22 @@ export function composeRuntime(options) {
1589
1629
  journal.record(`scoped refusal ${room.locator} ${result.scope} ${result.code}`);
1590
1630
  }
1591
1631
  async function synchronize(discovered, local, progress) {
1592
- const rooms = await Promise.allSettled(discovered.map((room)=>synchronizeRoom(room, local, progress)));
1593
- const failed = rooms.find((room)=>room.status === 'rejected');
1632
+ const prepared = await Promise.allSettled(discovered.map((room)=>prepareRoom(room, local, progress)));
1633
+ const ready = discovered.filter((_, index)=>{
1634
+ const outcome = prepared[index];
1635
+ return outcome?.status === 'fulfilled' && outcome.value;
1636
+ });
1637
+ const rooms = await Promise.allSettled(ready.map((room)=>synchronizeRoom(room, local, progress)));
1638
+ const failed = [
1639
+ ...prepared,
1640
+ ...rooms
1641
+ ].find((room)=>room.status === 'rejected');
1594
1642
  if (failed !== undefined) throw failed.reason;
1595
1643
  }
1596
- async function synchronizeRoom(room, local, progress) {
1644
+ async function prepareRoom(room, local, progress) {
1597
1645
  if (closed || authorization === undefined) {
1598
1646
  progress.complete = false;
1599
- return;
1647
+ return false;
1600
1648
  }
1601
1649
  const prior = replicas.get(room.locator)?.confirmed.record;
1602
1650
  if (prior !== undefined && prior.replica.selection !== room.replica.selection) {
@@ -1604,7 +1652,7 @@ export function composeRuntime(options) {
1604
1652
  emitRooms();
1605
1653
  journal.record(`selection changed ${room.locator}`);
1606
1654
  progress.complete = false;
1607
- return;
1655
+ return false;
1608
1656
  }
1609
1657
  const selection = room.typedSelection;
1610
1658
  await Promise.all([
@@ -1613,16 +1661,20 @@ export function composeRuntime(options) {
1613
1661
  acquireModel(local, room, authorization, selection)
1614
1662
  ]
1615
1663
  ]);
1616
- if (discoveryPaused || authorization === undefined) return;
1664
+ if (discoveryPaused || authorization === undefined) return false;
1617
1665
  if (room.replica.admission !== 'admitted') {
1618
1666
  progress.complete = false;
1619
- return;
1667
+ return false;
1620
1668
  }
1621
1669
  const held = replicas.get(room.locator);
1622
1670
  if (held !== undefined && held.confirmed.record.replica.selection !== room.replica.selection) {
1623
1671
  progress.complete = false;
1624
- return;
1672
+ return false;
1625
1673
  }
1674
+ return true;
1675
+ }
1676
+ async function synchronizeRoom(room, local, progress) {
1677
+ if (discoveryPaused || authorization === undefined) return;
1626
1678
  const withheld = await advance(room, local, authorization);
1627
1679
  if (withheld !== null) {
1628
1680
  await withhold(withheld, room, local, progress);
@@ -2212,6 +2264,9 @@ export function composeRuntime(options) {
2212
2264
  call (name, input) {
2213
2265
  return invokeAction(name, input);
2214
2266
  },
2267
+ reached (locator, roomVersion) {
2268
+ return reachedBy(locator, roomVersion);
2269
+ },
2215
2270
  log () {
2216
2271
  return journal.export();
2217
2272
  },