@ai-react-markdown/engine 2.9.0 → 2.10.0

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.
package/dist/index.dev.js CHANGED
@@ -370,16 +370,15 @@ function settleRefsAndEarliestUnresolved(cp) {
370
370
  var TYPE6_NAMES = new Set(htmlBlockNames);
371
371
  var TABLE_PART_NAMES = /* @__PURE__ */ new Set(["td", "th", "tr", "tbody", "thead", "tfoot", "caption", "col", "colgroup"]);
372
372
  var DOCUMENT_STRUCTURE_NAMES = /* @__PURE__ */ new Set(["html", "head", "body", "frameset"]);
373
+ var NO_ELEMENT_NAMES = /* @__PURE__ */ new Set([...DOCUMENT_STRUCTURE_NAMES, "frame", "image"]);
373
374
  var RETROACTIVE_OPENERS = [
374
375
  "<!doctype",
375
- "<html",
376
- "<head",
377
- "<body",
378
- "<frameset",
379
- "</html",
380
- "</head",
381
- "</body",
382
- "</frameset"
376
+ // DERIVED, so the trailing-partial guard cannot drift from the poison the
377
+ // confirmed lines get. It was transcribed until F28, and the transcription
378
+ // was already two names behind by then. `<frame` subsumes `<frameset`,
379
+ // which is why the derived list is SHORTER than the one it replaces and
380
+ // still covers strictly more.
381
+ ...[...NO_ELEMENT_NAMES].flatMap((name) => [`<${name}`, `</${name}`])
383
382
  ];
384
383
  function tailCarriesRetroactive(text) {
385
384
  const lower = text.toLowerCase();
@@ -632,6 +631,7 @@ function freshCheckpoint(defListEnabled, mathFlow, referenceTaint) {
632
631
  tagBalance: /* @__PURE__ */ new Map(),
633
632
  openTotal: 0,
634
633
  p5Tok: { kind: "data" },
634
+ formPointerMaybeSet: false,
635
635
  openStack: [],
636
636
  mdBlock: { kind: "none" },
637
637
  blankRun: 0,
@@ -782,6 +782,7 @@ function sealReleaseDerived(cp, ln, isBlockStart) {
782
782
  if (DEF_RE.test(ln.text) || FOOTNOTE_DEF_RE.test(ln.text)) return false;
783
783
  return true;
784
784
  }
785
+ var sealReleaseEvaluations = 0;
785
786
  function sealReleaseEnumerated(cp, ln, isBlockStart) {
786
787
  const defShapedLine = DEF_RE.test(ln.text) || FOOTNOTE_DEF_RE.test(ln.text) || cp.defBlockMaybeOpen || cp.fnDefResumable && !(isBlockStart && ln.indent <= 3);
787
788
  const commentOnly = ln.text.replace(/<!--[\s\S]*?-->/g, " ").replace(/<!--[\s\S]*$/, " ").replace(/[ \t\r]/g, "") === "";
@@ -796,10 +797,13 @@ function processConfirmedLine(cp, ln, text) {
796
797
  if (cp.p5SealPending && !ln.blank && cp.mdBlock.kind !== "html" && !(cp.p5Tok.kind === "comment" || cp.p5Tok.kind === "bogus")) {
797
798
  if (sealReleaseDerived(cp, ln, isBlockStart)) {
798
799
  cp.p5SealPending = false;
799
- if (!sealReleaseEnumerated(cp, ln, isBlockStart)) {
800
- console.error(
801
- `[ai-react-markdown] seal-release containment broken at offset ${ln.start}: the derived predicate released a line the retired enumeration withheld (${JSON.stringify(ln.text.slice(0, 80))}).`
802
- );
800
+ if (true) {
801
+ sealReleaseEvaluations += 1;
802
+ if (!sealReleaseEnumerated(cp, ln, isBlockStart)) {
803
+ console.error(
804
+ `[ai-react-markdown] seal-release containment broken at offset ${ln.start}: the derived predicate released a line the retired enumeration withheld (${JSON.stringify(ln.text.slice(0, 80))}).`
805
+ );
806
+ }
803
807
  }
804
808
  }
805
809
  }
@@ -828,7 +832,7 @@ function processConfirmedLine(cp, ln, text) {
828
832
  if (tag === "plaintext") cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
829
833
  }
830
834
  }
831
- if (DOCUMENT_STRUCTURE_NAMES.has(tag)) cp.phasePoisonedAt = 0;
835
+ if (NO_ELEMENT_NAMES.has(tag)) cp.phasePoisonedAt = 0;
832
836
  if (tag === "template" && !closing) cp.phasePoisonedAt = 0;
833
837
  if (closing) {
834
838
  let idx = -1;
@@ -844,12 +848,14 @@ function processConfirmedLine(cp, ln, text) {
844
848
  return;
845
849
  }
846
850
  cp.openStack.splice(idx, 1);
851
+ if (tag === "form") cp.formPointerMaybeSet = false;
847
852
  const count = cp.tagBalance.get(tag) ?? 0;
848
853
  if (count > 0) {
849
854
  cp.tagBalance.set(tag, count - 1);
850
855
  cp.openTotal -= 1;
851
856
  }
852
857
  } else {
858
+ if (tag === "form") cp.formPointerMaybeSet = true;
853
859
  cp.openStack.push(tag);
854
860
  cp.tagBalance.set(tag, (cp.tagBalance.get(tag) ?? 0) + 1);
855
861
  cp.openTotal += 1;
@@ -976,7 +982,11 @@ function processConfirmedLine(cp, ln, text) {
976
982
  // mask suppresses them — which is exactly why `openTotal` reads 0
977
983
  // and the candidate looked safe), and the 2-5 interiors are the
978
984
  // same construct to both grammars.
979
- htmlBalanced: cp.openTotal === 0 && cp.mdBlock.kind !== "html" && cp.p5Tok.kind !== "bogus",
985
+ htmlBalanced: cp.openTotal === 0 && cp.mdBlock.kind !== "html" && cp.p5Tok.kind !== "bogus" && // A form pointer parse5 may still be holding makes a LATER `<form>`
986
+ // in the tail vanish from the full parse while a split parse opens
987
+ // it — forward independence fails with every other condition clean.
988
+ // See the field doc.
989
+ !cp.formPointerMaybeSet,
980
990
  hazard: cp.hazardVerdict,
981
991
  seamRisk: cp.p5SealPending,
982
992
  defListSettled: null
@@ -1372,6 +1382,11 @@ var SCANNER_NAME_LISTS = [
1372
1382
  ["type6", TYPE6_NAMES],
1373
1383
  ["void", VOID_TAGS],
1374
1384
  ["documentStructure", DOCUMENT_STRUCTURE_NAMES],
1385
+ // Added with F28, and it is the list that would have made F28 visible: the
1386
+ // derived census alphabet partitions names by their membership across THIS
1387
+ // table, so before it existed `frame` shared one 39-name class with `div`
1388
+ // and could never be sampled apart from it.
1389
+ ["noElement", NO_ELEMENT_NAMES],
1375
1390
  ["tablePart", TABLE_PART_NAMES],
1376
1391
  ["scopeBarrier", SCOPE_BARRIER_NAMES],
1377
1392
  ["foreignRoot", new Set(FOREIGN_ROOT_NAMES)]
@@ -4339,24 +4354,32 @@ var SMOOTH_STREAM_PACING_PRESETS = Object.freeze({
4339
4354
  correctionTauMs: 280,
4340
4355
  emaTauMs: 2600,
4341
4356
  minCharsPerSecond: 4,
4342
- drainMs: 320
4357
+ drainMs: 320,
4358
+ maxLagMs: 3500
4343
4359
  }),
4344
4360
  balanced: Object.freeze({
4345
4361
  bufferFactor: 1,
4346
4362
  correctionTauMs: 180,
4347
4363
  emaTauMs: 1800,
4348
4364
  minCharsPerSecond: 6,
4349
- drainMs: 240
4365
+ drainMs: 240,
4366
+ maxLagMs: 2500
4350
4367
  }),
4351
4368
  responsive: Object.freeze({
4352
4369
  bufferFactor: 0.45,
4353
4370
  correctionTauMs: 110,
4354
4371
  emaTauMs: 1100,
4355
4372
  minCharsPerSecond: 10,
4356
- drainMs: 150
4373
+ drainMs: 150,
4374
+ maxLagMs: 800
4357
4375
  })
4358
4376
  });
4359
- var MAX_TARGET_BUFFER_MS = 1200;
4377
+ var GAP_WINDOW = 16;
4378
+ var INTERVAL_QUANTILE = 0.9;
4379
+ var HORIZON_PAD_MS = 50;
4380
+ var DEADLINE_FLOOR_MS = 33;
4381
+ var DRAIN_CATCHUP_FACTOR = 2;
4382
+ var DRAIN_MAX_FACTOR = 3;
4360
4383
  var defaultNow = typeof performance !== "undefined" && typeof performance.now === "function" ? () => performance.now() : () => Date.now();
4361
4384
  var defaultSchedule = (cb) => {
4362
4385
  if (typeof requestAnimationFrame === "function") {
@@ -4407,18 +4430,18 @@ var createSmoothStreamController = (options = {}) => {
4407
4430
  let lastTickAt = 0;
4408
4431
  let cancelFrame;
4409
4432
  let disposed = false;
4410
- let rateEma;
4411
- let intervalEma;
4433
+ let gapWindow = [];
4412
4434
  let lastArrivalAt;
4413
4435
  const listeners = /* @__PURE__ */ new Set();
4414
4436
  const resolveParams = () => {
4415
- const preset = SMOOTH_STREAM_PACING_PRESETS[options.pacing] ?? SMOOTH_STREAM_PACING_PRESETS.balanced;
4437
+ const preset = Object.hasOwn(SMOOTH_STREAM_PACING_PRESETS, options.pacing) ? SMOOTH_STREAM_PACING_PRESETS[options.pacing] : SMOOTH_STREAM_PACING_PRESETS.balanced;
4416
4438
  return {
4417
4439
  bufferFactor: finiteOr(options.bufferFactor, preset.bufferFactor),
4418
4440
  correctionTauMs: finiteOr(options.correctionTauMs, preset.correctionTauMs),
4419
4441
  emaTauMs: finiteOr(options.emaTauMs, preset.emaTauMs),
4420
4442
  minCharsPerSecond: finiteOr(options.minCharsPerSecond, preset.minCharsPerSecond),
4421
- drainMs: finiteOr(options.drainMs, preset.drainMs)
4443
+ drainMs: finiteOr(options.drainMs, preset.drainMs),
4444
+ maxLagMs: finiteOr(options.maxLagMs, preset.maxLagMs ?? 2500)
4422
4445
  };
4423
4446
  };
4424
4447
  const recordArrival = (t, added) => {
@@ -4429,12 +4452,8 @@ var createSmoothStreamController = (options = {}) => {
4429
4452
  }
4430
4453
  const gap = Math.max(1, t - lastArrivalAt);
4431
4454
  lastArrivalAt = t;
4432
- const tau = Math.max(1, resolveParams().emaTauMs);
4433
- if (gap > tau) return;
4434
- const alpha = 1 - Math.exp(-gap / tau);
4435
- const instantRate = added * 1e3 / gap;
4436
- rateEma = (rateEma ?? 0) + alpha * (instantRate - (rateEma ?? 0));
4437
- intervalEma = (intervalEma ?? 0) + alpha * (gap - (intervalEma ?? 0));
4455
+ gapWindow.push({ gap, added });
4456
+ if (gapWindow.length > GAP_WINDOW) gapWindow.shift();
4438
4457
  };
4439
4458
  const notify = () => {
4440
4459
  visibleCache = source.slice(0, visibleEnd);
@@ -4460,15 +4479,12 @@ var createSmoothStreamController = (options = {}) => {
4460
4479
  let rate;
4461
4480
  if (finished && drainDeadlineAt !== void 0) {
4462
4481
  rate = Math.max(params.minCharsPerSecond, pending.length * 1e3 / Math.max(1, drainDeadlineAt - t));
4463
- } else if (rateEma !== void 0 && intervalEma !== void 0) {
4464
- const targetBuffer = Math.max(
4465
- 1,
4466
- Math.min(params.bufferFactor * rateEma * (intervalEma / 1e3), rateEma * MAX_TARGET_BUFFER_MS / 1e3)
4467
- );
4468
- rate = Math.max(
4469
- params.minCharsPerSecond,
4470
- rateEma + (pending.length - targetBuffer) * 1e3 / Math.max(1, params.correctionTauMs)
4471
- );
4482
+ } else if (gapWindow.length > 0 && lastArrivalAt !== void 0) {
4483
+ const gaps = gapWindow.map((s) => s.gap).sort((a, b) => a - b);
4484
+ const intervalQ = gaps[Math.min(gaps.length - 1, Math.floor(gaps.length * INTERVAL_QUANTILE))];
4485
+ const horizon = Math.max(16, Math.min(params.bufferFactor * intervalQ + HORIZON_PAD_MS, params.maxLagMs));
4486
+ const deadline = Math.max(lastArrivalAt + horizon, t + DEADLINE_FLOOR_MS);
4487
+ rate = Math.max(params.minCharsPerSecond, pending.length * 1e3 / Math.max(1, deadline - t));
4472
4488
  } else {
4473
4489
  rate = Math.max(params.minCharsPerSecond, pending.length * 1e3 / Math.max(1, params.correctionTauMs));
4474
4490
  }
@@ -4514,8 +4530,7 @@ var createSmoothStreamController = (options = {}) => {
4514
4530
  initialized = true;
4515
4531
  finished = false;
4516
4532
  drainDeadlineAt = void 0;
4517
- rateEma = void 0;
4518
- intervalEma = void 0;
4533
+ gapWindow = [];
4519
4534
  lastArrivalAt = void 0;
4520
4535
  source = next;
4521
4536
  visibleEnd = next.length;
@@ -4552,10 +4567,26 @@ var createSmoothStreamController = (options = {}) => {
4552
4567
  if (finished) return;
4553
4568
  finished = true;
4554
4569
  lastArrivalAt = void 0;
4555
- drainDeadlineAt = now() + resolveParams().drainMs;
4556
4570
  if (tentativeEnd > (pending.length > 0 ? pending[pending.length - 1] : visibleEnd)) {
4557
4571
  pending.push(tentativeEnd);
4558
4572
  }
4573
+ const params = resolveParams();
4574
+ let drainWin = params.drainMs;
4575
+ let chars = 0;
4576
+ let ms = 0;
4577
+ for (let i = 0; i < gapWindow.length - 1; i += 1) {
4578
+ chars += gapWindow[i].added;
4579
+ ms += gapWindow[i].gap;
4580
+ }
4581
+ const backlog = source.length - visibleEnd;
4582
+ if (chars > 0 && ms > 0 && backlog > 0) {
4583
+ const throughput = chars * 1e3 / ms;
4584
+ drainWin = Math.min(
4585
+ Math.max(backlog * 1e3 / (DRAIN_CATCHUP_FACTOR * throughput), params.drainMs),
4586
+ DRAIN_MAX_FACTOR * params.drainMs
4587
+ );
4588
+ }
4589
+ drainDeadlineAt = now() + drainWin;
4559
4590
  seam = source.length;
4560
4591
  ensureScheduled();
4561
4592
  },