@dudousxd/nestjs-agent 1.36.1 → 1.37.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.cjs CHANGED
@@ -1676,6 +1676,26 @@ var RunNotActiveException = class extends import_common5.ConflictException {
1676
1676
  }
1677
1677
  };
1678
1678
 
1679
+ // src/thread-reads.ts
1680
+ function threadReads(store, threadId, separately) {
1681
+ const projecting = store;
1682
+ if (typeof projecting.threadSettings !== "function") {
1683
+ return separately;
1684
+ }
1685
+ let settings;
1686
+ const read = /* @__PURE__ */ __name(() => {
1687
+ settings ??= projecting.threadSettings?.(threadId) ?? Promise.resolve(null);
1688
+ return settings;
1689
+ }, "read");
1690
+ return {
1691
+ owner: /* @__PURE__ */ __name(async () => (await read())?.actorRef ?? null, "owner"),
1692
+ defaultAgent: /* @__PURE__ */ __name(async () => (await read())?.defaultAgent ?? null, "defaultAgent"),
1693
+ persona: /* @__PURE__ */ __name(async () => (await read())?.persona ?? null, "persona"),
1694
+ model: /* @__PURE__ */ __name(async () => (await read())?.model ?? null, "model")
1695
+ };
1696
+ }
1697
+ __name(threadReads, "threadReads");
1698
+
1679
1699
  // src/agent.service.ts
1680
1700
  function _ts_decorate5(decorators, target, key, desc) {
1681
1701
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -1939,7 +1959,7 @@ var AgentService2 = class {
1939
1959
  * else the thread's pinned one, else none. An agent the catalog locks to one model runs on it
1940
1960
  * whatever was sent or pinned, and a send naming another model is refused.
1941
1961
  */
1942
- async resolveModel(actor, agent, requested, threadId) {
1962
+ async resolveModel(actor, agent, requested, threadId, reads) {
1943
1963
  const locked = this.models !== void 0 ? (await this.models.list({
1944
1964
  actor,
1945
1965
  agent
@@ -1950,7 +1970,7 @@ var AgentService2 = class {
1950
1970
  }
1951
1971
  return locked.model;
1952
1972
  }
1953
- const model = requested ?? (threadId !== void 0 ? await this.threadModel(threadId) : null);
1973
+ const model = requested ?? (threadId !== void 0 ? await (reads?.model() ?? this.threadModel(threadId)) : null);
1954
1974
  if (model === null || model === void 0) {
1955
1975
  return void 0;
1956
1976
  }
@@ -2010,10 +2030,11 @@ var AgentService2 = class {
2010
2030
  if ("proposalDecision" in decision) return decision;
2011
2031
  }
2012
2032
  await this.assertWithinQuota(params.actor);
2013
- const target = this.deps.resolveAgent(await this.resolveAgentName(params.agentName, params.threadId));
2033
+ const reads = params.threadId !== void 0 ? this.threadReads(params.threadId) : void 0;
2034
+ const target = this.deps.resolveAgent(await this.resolveAgentName(params.agentName, params.threadId, reads));
2014
2035
  const agentName = target.agentName;
2015
- const persona = await this.resolvePersona(agentName, params.personaId ?? target.persona, params.threadId);
2016
- const model = await this.resolveModel(params.actor, agentName, params.model, params.threadId);
2036
+ const persona = await this.resolvePersona(agentName, params.personaId ?? target.persona, params.threadId, reads);
2037
+ const model = await this.resolveModel(params.actor, agentName, params.model, params.threadId, reads);
2017
2038
  const attachments = await this.resolveAttachments(params.actor, params.attachments ?? []);
2018
2039
  let threadId = params.threadId;
2019
2040
  if (threadId === void 0) {
@@ -2037,9 +2058,9 @@ var AgentService2 = class {
2037
2058
  });
2038
2059
  threadId = created.id;
2039
2060
  } else {
2040
- if (params.authorized !== true) await this.assertOwnsThread(params.actor, threadId);
2061
+ if (params.authorized !== true) await this.assertOwnsThread(params.actor, threadId, reads);
2041
2062
  if (params.personaId !== void 0) {
2042
- await this.pinThreadPersona(threadId, params.personaId);
2063
+ await this.pinThreadPersona(threadId, params.personaId, reads);
2043
2064
  }
2044
2065
  }
2045
2066
  const input = {
@@ -2365,8 +2386,8 @@ var AgentService2 = class {
2365
2386
  * {@link subscribeAs} instead: a runId is the only thing standing between a caller and another
2366
2387
  * actor's answer, tool arguments and tool results.
2367
2388
  */
2368
- subscribe(runId) {
2369
- return this.deps.forAgent().sink.subscribe(runId);
2389
+ subscribe(runId, options) {
2390
+ return this.deps.forAgent().sink.subscribe(runId, options);
2370
2391
  }
2371
2392
  /**
2372
2393
  * {@link subscribe}, gated the way {@link cancel} is: only the actor whose thread is currently
@@ -2374,9 +2395,9 @@ var AgentService2 = class {
2374
2395
  * replayed — the runner clears the thread's active stream as the run ends, and that field is what
2375
2396
  * ownership is derived from.
2376
2397
  */
2377
- async subscribeAs(actor, runId) {
2398
+ async subscribeAs(actor, runId, options) {
2378
2399
  await this.assertOwnsActiveStream(actor, runId);
2379
- return this.subscribe(runId);
2400
+ return this.subscribe(runId, options);
2380
2401
  }
2381
2402
  /**
2382
2403
  * Approve a parked action call as `actor`. Who may is the call's recorded approver's business
@@ -2529,9 +2550,28 @@ var AgentService2 = class {
2529
2550
  await this.assertOwnsThread(actor, threadId);
2530
2551
  return this.store.softDeleteThread(threadId);
2531
2552
  }
2532
- async forkThread(actor, threadId, fromMessageId) {
2533
- await this.assertOwnsThread(actor, threadId);
2534
- return this.store.forkThread(threadId, fromMessageId);
2553
+ /**
2554
+ * Copy a thread up to `fromMessageId` (inclusive) into a new one. By default only the thread's
2555
+ * owner may, and the copy is theirs. With `params.authorized`, the host has vouched for `actor`
2556
+ * (a share link it checked) and the copy is `actor`'s — see {@link ForkThreadParams}.
2557
+ */
2558
+ async forkThread(actor, threadId, fromMessageId, params = {}) {
2559
+ if (params.authorized === true) {
2560
+ if (await this.store.ownerOfThread(threadId) === null) {
2561
+ throw new import_common6.NotFoundException(`thread ${threadId} not found`);
2562
+ }
2563
+ } else {
2564
+ await this.assertOwnsThread(actor, threadId);
2565
+ }
2566
+ const options = {
2567
+ ...params.authorized === true ? {
2568
+ actorRef: actor.id
2569
+ } : {},
2570
+ ...params.tenantRef !== void 0 ? {
2571
+ tenantRef: params.tenantRef
2572
+ } : {}
2573
+ };
2574
+ return this.store.forkThread(threadId, fromMessageId, options);
2535
2575
  }
2536
2576
  /** Kept for source compatibility — a thin wrapper over the more general `updateThread`. */
2537
2577
  async renameThread(actor, threadId, title) {
@@ -2583,7 +2623,7 @@ var AgentService2 = class {
2583
2623
  * The persona this send runs under — see {@link AgentDepsFactory.resolvePersona}. The thread's
2584
2624
  * pinned persona is read only when the send names none AND the agent has personas to pick from.
2585
2625
  */
2586
- async resolvePersona(agentName, requested, threadId) {
2626
+ async resolvePersona(agentName, requested, threadId, reads) {
2587
2627
  const needsThread = requested === void 0 && threadId !== void 0 && this.deps.personaCatalog(agentName).length > 0;
2588
2628
  return this.deps.resolvePersona({
2589
2629
  agentName,
@@ -2591,16 +2631,16 @@ var AgentService2 = class {
2591
2631
  requested
2592
2632
  } : {},
2593
2633
  ...needsThread ? {
2594
- threadPersona: await threadPersona(this.store, threadId)
2634
+ threadPersona: await (reads?.persona() ?? threadPersona(this.store, threadId))
2595
2635
  } : {}
2596
2636
  });
2597
2637
  }
2598
2638
  /** Pin `persona` on the thread when it is not already — a no-op on a store that cannot. */
2599
- async pinThreadPersona(threadId, persona) {
2639
+ async pinThreadPersona(threadId, persona, reads) {
2600
2640
  if (this.store.updateThread === void 0) {
2601
2641
  return;
2602
2642
  }
2603
- if (await threadPersona(this.store, threadId) !== persona) {
2643
+ if (await (reads?.persona() ?? threadPersona(this.store, threadId)) !== persona) {
2604
2644
  await this.store.updateThread(threadId, {
2605
2645
  persona
2606
2646
  });
@@ -2627,18 +2667,27 @@ var AgentService2 = class {
2627
2667
  * workflow, for a string. A store predating {@link ThreadDefaultAgentReader} still answers, via
2628
2668
  * the full read.
2629
2669
  */
2630
- async resolveAgentName(agentName, threadId) {
2670
+ async resolveAgentName(agentName, threadId, reads) {
2631
2671
  if (agentName !== void 0) {
2632
2672
  return agentName;
2633
2673
  }
2634
2674
  if (threadId !== void 0) {
2635
- const threadDefault = await this.threadDefaultAgent(threadId);
2675
+ const threadDefault = await (reads?.defaultAgent() ?? this.threadDefaultAgent(threadId));
2636
2676
  if (threadDefault !== null) {
2637
2677
  return threadDefault;
2638
2678
  }
2639
2679
  }
2640
2680
  return this.deps.defaultAgentName();
2641
2681
  }
2682
+ /** Everything a send reads off `threadId`, in one read where the store allows it. */
2683
+ threadReads(threadId) {
2684
+ return threadReads(this.store, threadId, {
2685
+ owner: /* @__PURE__ */ __name(() => this.store.ownerOfThread(threadId), "owner"),
2686
+ defaultAgent: /* @__PURE__ */ __name(() => this.threadDefaultAgent(threadId), "defaultAgent"),
2687
+ persona: /* @__PURE__ */ __name(() => threadPersona(this.store, threadId), "persona"),
2688
+ model: /* @__PURE__ */ __name(() => this.threadModel(threadId), "model")
2689
+ });
2690
+ }
2642
2691
  async threadDefaultAgent(threadId) {
2643
2692
  const projecting = this.store;
2644
2693
  if (typeof projecting.defaultAgentForThread === "function") {
@@ -2808,8 +2857,8 @@ var AgentService2 = class {
2808
2857
  * Authorization seam for thread-scoped endpoints: the caller must own the thread. A missing
2809
2858
  * thread is a 404; someone else's thread is a 403 — one actor never touches another's thread.
2810
2859
  */
2811
- async assertOwnsThread(actor, threadId) {
2812
- const owner = await this.store.ownerOfThread(threadId);
2860
+ async assertOwnsThread(actor, threadId, reads) {
2861
+ const owner = await (reads?.owner() ?? this.store.ownerOfThread(threadId));
2813
2862
  if (owner === null) {
2814
2863
  throw new import_common6.NotFoundException(`thread ${threadId} not found`);
2815
2864
  }
@@ -3249,6 +3298,18 @@ AttachmentsController = _ts_decorate8([
3249
3298
  var import_nestjs_agent_core12 = require("@dudousxd/nestjs-agent-core");
3250
3299
  var import_genui2 = require("@dudousxd/nestjs-agent-core/genui");
3251
3300
  var import_common10 = require("@nestjs/common");
3301
+
3302
+ // src/controller/reader-gone.ts
3303
+ function readerGone(res) {
3304
+ const controller = new AbortController();
3305
+ res.once("close", () => controller.abort());
3306
+ return {
3307
+ signal: controller.signal
3308
+ };
3309
+ }
3310
+ __name(readerGone, "readerGone");
3311
+
3312
+ // src/controller/chat.controller.ts
3252
3313
  function _ts_decorate9(decorators, target, key, desc) {
3253
3314
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3254
3315
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -3382,7 +3443,8 @@ var ChatController = class {
3382
3443
  return;
3383
3444
  }
3384
3445
  const { runId, threadId } = result;
3385
- await this.pipe(res, runId, this.agent.subscribe(runId), threadId);
3446
+ const gone = readerGone(res);
3447
+ await this.pipe(res, runId, this.agent.subscribe(runId, gone), threadId, 0, gone.signal);
3386
3448
  }
3387
3449
  /**
3388
3450
  * Attach to a run's stream: every buffered frame, then live ones. `?after=<seq>` (or the SSE
@@ -3392,7 +3454,8 @@ var ChatController = class {
3392
3454
  async stream(req, runId, res, after) {
3393
3455
  const actor = await this.actorResolver.resolve(req);
3394
3456
  const cursor = parseCursor(after) ?? parseCursor(req.headers["last-event-id"]) ?? 0;
3395
- await this.pipe(res, runId, await this.agent.subscribeAs(actor, runId), void 0, cursor);
3457
+ const gone = readerGone(res);
3458
+ await this.pipe(res, runId, await this.agent.subscribeAs(actor, runId, gone), void 0, cursor, gone.signal);
3396
3459
  }
3397
3460
  async cancel(req, runId) {
3398
3461
  const actor = await this.actorResolver.resolve(req);
@@ -3408,8 +3471,11 @@ var ChatController = class {
3408
3471
  * and on any later `GET …/stream`, whichever replica serves it. A reconnecting client passes the
3409
3472
  * last one it saw as `?after=`; frames at or below it are read off the sink but not re-sent.
3410
3473
  * `meta`, `done` and `error` carry no id: `meta` is re-sent on every attach, the terminals once.
3474
+ *
3475
+ * A reader that disconnects aborts `gone`, which the sink honours by ending the subscription even
3476
+ * while the run is silent (parked on a person, or never writing again).
3411
3477
  */
3412
- async pipe(res, runId, events, threadId, after = 0) {
3478
+ async pipe(res, runId, events, threadId, after = 0, gone) {
3413
3479
  res.setHeader("Content-Type", "text/event-stream");
3414
3480
  res.setHeader("Cache-Control", "no-cache");
3415
3481
  res.setHeader("Connection", "keep-alive");
@@ -3438,6 +3504,9 @@ data: ${line}
3438
3504
  }, "forward");
3439
3505
  try {
3440
3506
  for await (const chunk of events) {
3507
+ if (gone?.aborted) {
3508
+ return;
3509
+ }
3441
3510
  buffer += decoder.decode(chunk, {
3442
3511
  stream: true
3443
3512
  });
@@ -3451,11 +3520,17 @@ data: ${line}
3451
3520
  newline = buffer.indexOf("\n");
3452
3521
  }
3453
3522
  }
3523
+ if (gone?.aborted) {
3524
+ return;
3525
+ }
3454
3526
  if (buffer.length > 0) {
3455
3527
  forward(buffer);
3456
3528
  }
3457
3529
  res.write("event: done\ndata: {}\n\n");
3458
3530
  } catch (error) {
3531
+ if (gone?.aborted) {
3532
+ return;
3533
+ }
3459
3534
  const payload = error instanceof import_nestjs_agent_core12.AgentStreamError ? {
3460
3535
  code: error.code,
3461
3536
  message: error.message
@@ -5385,49 +5460,121 @@ SkillDiscoveryService = _ts_decorate22([
5385
5460
 
5386
5461
  // src/in-process-sink.ts
5387
5462
  var import_nestjs_agent_core27 = require("@dudousxd/nestjs-agent-core");
5463
+ var LIVE_TTL_MS = 36e5;
5464
+ var ENDED_GRACE_MS = 6e4;
5388
5465
  var InProcessTokenStreamSink = class {
5389
5466
  static {
5390
5467
  __name(this, "InProcessTokenStreamSink");
5391
5468
  }
5392
5469
  runs = /* @__PURE__ */ new Map();
5470
+ /** Subscribers of a run nothing has opened yet, woken by its `open()`. */
5471
+ waiting = /* @__PURE__ */ new Map();
5393
5472
  buffer(runId) {
5394
5473
  let buf = this.runs.get(runId);
5395
5474
  if (buf === void 0) {
5396
5475
  buf = {
5397
5476
  chunks: [],
5398
5477
  ended: false,
5399
- notify: /* @__PURE__ */ new Set()
5478
+ notify: /* @__PURE__ */ new Set(),
5479
+ lastWriteAt: Date.now(),
5480
+ expiry: void 0
5400
5481
  };
5401
5482
  this.runs.set(runId, buf);
5483
+ this.expireAfter(runId, buf, LIVE_TTL_MS);
5484
+ const waiters = this.waiting.get(runId);
5485
+ this.waiting.delete(runId);
5486
+ for (const resolve2 of waiters ?? []) {
5487
+ resolve2();
5488
+ }
5402
5489
  }
5403
5490
  return buf;
5404
5491
  }
5492
+ expireAfter(runId, buf, ms) {
5493
+ if (buf.expiry !== void 0) {
5494
+ clearTimeout(buf.expiry);
5495
+ }
5496
+ buf.expiry = setTimeout(() => {
5497
+ buf.expiry = void 0;
5498
+ const idle = Date.now() - buf.lastWriteAt;
5499
+ if (!buf.ended && idle < LIVE_TTL_MS) {
5500
+ this.expireAfter(runId, buf, LIVE_TTL_MS - idle);
5501
+ return;
5502
+ }
5503
+ this.drop(runId, buf);
5504
+ }, ms);
5505
+ buf.expiry.unref?.();
5506
+ }
5507
+ /** Forget the run, and let anyone still following it finish as if it had ended. */
5508
+ drop(runId, buf) {
5509
+ if (buf.expiry !== void 0) {
5510
+ clearTimeout(buf.expiry);
5511
+ buf.expiry = void 0;
5512
+ }
5513
+ if (this.runs.get(runId) === buf) {
5514
+ this.runs.delete(runId);
5515
+ }
5516
+ buf.ended = true;
5517
+ this.wake(buf);
5518
+ }
5405
5519
  wake(buf) {
5406
5520
  for (const resolve2 of buf.notify) {
5407
5521
  resolve2();
5408
5522
  }
5409
5523
  buf.notify.clear();
5410
5524
  }
5525
+ finish(runId, buf) {
5526
+ buf.ended = true;
5527
+ this.wake(buf);
5528
+ this.expireAfter(runId, buf, ENDED_GRACE_MS);
5529
+ }
5530
+ /**
5531
+ * The run's writer. Each call finds the run's buffer afresh, so a run that went quiet past the
5532
+ * live TTL (parked on a person) and then writes again starts a new buffer its next subscriber
5533
+ * follows, rather than writing into one nothing reads.
5534
+ */
5411
5535
  open(runId) {
5412
- const buf = this.buffer(runId);
5536
+ this.buffer(runId);
5413
5537
  return {
5414
5538
  write: /* @__PURE__ */ __name((chunk) => {
5539
+ const buf = this.buffer(runId);
5415
5540
  buf.chunks.push(chunk);
5541
+ buf.lastWriteAt = Date.now();
5416
5542
  this.wake(buf);
5417
5543
  }, "write"),
5418
5544
  end: /* @__PURE__ */ __name(() => {
5419
- buf.ended = true;
5420
- this.wake(buf);
5545
+ this.finish(runId, this.buffer(runId));
5421
5546
  }, "end"),
5422
5547
  fail: /* @__PURE__ */ __name((error) => {
5548
+ const buf = this.buffer(runId);
5423
5549
  buf.failure = error;
5424
- buf.ended = true;
5425
- this.wake(buf);
5550
+ this.finish(runId, buf);
5426
5551
  }, "fail")
5427
5552
  };
5428
5553
  }
5429
- async *subscribe(runId) {
5430
- const buf = this.buffer(runId);
5554
+ async *subscribe(runId, options = {}) {
5555
+ const { signal } = options;
5556
+ let buf = this.runs.get(runId);
5557
+ while (buf === void 0) {
5558
+ const waiters = this.waiting.get(runId) ?? /* @__PURE__ */ new Set();
5559
+ this.waiting.set(runId, waiters);
5560
+ let resolve2 = /* @__PURE__ */ __name(() => {
5561
+ }, "resolve");
5562
+ const opened = new Promise((r) => {
5563
+ resolve2 = r;
5564
+ });
5565
+ waiters.add(resolve2);
5566
+ try {
5567
+ if (!await untilAborted(opened, signal)) {
5568
+ return;
5569
+ }
5570
+ } finally {
5571
+ waiters.delete(resolve2);
5572
+ if (waiters.size === 0 && this.waiting.get(runId) === waiters) {
5573
+ this.waiting.delete(runId);
5574
+ }
5575
+ }
5576
+ buf = this.runs.get(runId);
5577
+ }
5431
5578
  let index = 0;
5432
5579
  while (true) {
5433
5580
  while (index < buf.chunks.length) {
@@ -5443,13 +5590,56 @@ var InProcessTokenStreamSink = class {
5443
5590
  }
5444
5591
  return;
5445
5592
  }
5446
- await new Promise((resolve2) => buf.notify.add(resolve2));
5593
+ const current = buf;
5594
+ let resolve2 = /* @__PURE__ */ __name(() => {
5595
+ }, "resolve");
5596
+ const woken = new Promise((r) => {
5597
+ resolve2 = r;
5598
+ });
5599
+ current.notify.add(resolve2);
5600
+ try {
5601
+ if (!await untilAborted(woken, signal)) {
5602
+ return;
5603
+ }
5604
+ } finally {
5605
+ current.notify.delete(resolve2);
5606
+ }
5447
5607
  }
5448
5608
  }
5449
5609
  close(runId) {
5610
+ const buf = this.runs.get(runId);
5611
+ if (buf?.expiry !== void 0) {
5612
+ clearTimeout(buf.expiry);
5613
+ }
5450
5614
  this.runs.delete(runId);
5451
5615
  }
5452
5616
  };
5617
+ async function untilAborted(promise, signal) {
5618
+ if (signal === void 0) {
5619
+ await promise;
5620
+ return true;
5621
+ }
5622
+ if (signal.aborted) {
5623
+ return false;
5624
+ }
5625
+ let onAbort = /* @__PURE__ */ __name(() => {
5626
+ }, "onAbort");
5627
+ const aborted = new Promise((resolve2) => {
5628
+ onAbort = /* @__PURE__ */ __name(() => resolve2(false), "onAbort");
5629
+ signal.addEventListener("abort", onAbort, {
5630
+ once: true
5631
+ });
5632
+ });
5633
+ try {
5634
+ return await Promise.race([
5635
+ promise.then(() => true),
5636
+ aborted
5637
+ ]);
5638
+ } finally {
5639
+ signal.removeEventListener("abort", onAbort);
5640
+ }
5641
+ }
5642
+ __name(untilAborted, "untilAborted");
5453
5643
 
5454
5644
  // src/ledger-quota-provider.ts
5455
5645
  var import_nestjs_agent_core28 = require("@dudousxd/nestjs-agent-core");
@@ -5468,13 +5658,22 @@ var LedgerQuotaProvider = class {
5468
5658
  async report(query) {
5469
5659
  const now = query.now ?? /* @__PURE__ */ new Date();
5470
5660
  const actorRef = query.actor.id;
5471
- const windows = [
5472
- await this.dayWindow(actorRef, now)
5473
- ];
5474
- if (this.store.usageBetween !== void 0) {
5475
- const range = (0, import_nestjs_agent_core28.quotaPeriodRange)("month", now);
5476
- const used = await this.store.usageBetween(actorRef, range.fromDay, range.toDay);
5477
- windows.push(this.window("month", used.usedTokens, this.usd(used), range.resetsAt));
5661
+ const day = (0, import_nestjs_agent_core28.quotaPeriodRange)("day", now);
5662
+ const month = (0, import_nestjs_agent_core28.quotaPeriodRange)("month", now);
5663
+ const windows = [];
5664
+ if (this.store.usageWindows !== void 0) {
5665
+ const [dayUsed, monthUsed] = await this.store.usageWindows(actorRef, [
5666
+ day,
5667
+ month
5668
+ ]);
5669
+ windows.push(this.usedWindow("day", dayUsed, day.resetsAt));
5670
+ windows.push(this.usedWindow("month", monthUsed, month.resetsAt));
5671
+ } else {
5672
+ windows.push(this.usedWindow("day", await this.store.quotaToday(actorRef, day.fromDay), day.resetsAt));
5673
+ if (this.store.usageBetween !== void 0) {
5674
+ const used = await this.store.usageBetween(actorRef, month.fromDay, month.toDay);
5675
+ windows.push(this.usedWindow("month", used, month.resetsAt));
5676
+ }
5478
5677
  }
5479
5678
  const blocked = (0, import_nestjs_agent_core28.exhaustedWindow)(windows);
5480
5679
  const warning = (0, import_nestjs_agent_core28.quotaWarning)(windows);
@@ -5488,10 +5687,8 @@ var LedgerQuotaProvider = class {
5488
5687
  } : {}
5489
5688
  };
5490
5689
  }
5491
- async dayWindow(actorRef, now) {
5492
- const range = (0, import_nestjs_agent_core28.quotaPeriodRange)("day", now);
5493
- const used = await this.store.quotaToday(actorRef, range.fromDay);
5494
- return this.window("day", used.usedTokens, this.usd(used), range.resetsAt);
5690
+ usedWindow(period, used, resetsAt) {
5691
+ return this.window(period, used?.usedTokens ?? 0, used === void 0 ? 0 : this.usd(used), resetsAt);
5495
5692
  }
5496
5693
  /** The window's USD: every priced row, or (with `countEstimatedCost: false`) reported cost only. */
5497
5694
  usd(used) {
@@ -7336,7 +7533,7 @@ var AgUiRunHandler = class {
7336
7533
  seq: 0
7337
7534
  };
7338
7535
  try {
7339
- const frames = (0, import_ag_ui.agUiFramesFromNdjson)(this.agent.subscribe(runId));
7536
+ const frames = (0, import_ag_ui.agUiFramesFromNdjson)(this.agent.subscribe(runId, readerGone(res)));
7340
7537
  for await (const event of (0, import_ag_ui.agUiEvents)(frames, {
7341
7538
  ...options,
7342
7539
  cursor
@@ -7667,7 +7864,7 @@ var A2uiRunHandler = class {
7667
7864
  `);
7668
7865
  }, "write");
7669
7866
  try {
7670
- const frames = (0, import_ag_ui2.agUiFramesFromNdjson)(this.agent.subscribe(runId));
7867
+ const frames = (0, import_ag_ui2.agUiFramesFromNdjson)(this.agent.subscribe(runId, readerGone(res)));
7671
7868
  for await (const event of (0, import_ag_ui2.agUiEvents)(frames, {
7672
7869
  threadId: options.threadId ?? runId,
7673
7870
  runId,