@ouro.bot/cli 0.1.0-alpha.600 → 0.1.0-alpha.601

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/changelog.json CHANGED
@@ -1,6 +1,12 @@
1
1
  {
2
2
  "_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
3
3
  "versions": [
4
+ {
5
+ "version": "0.1.0-alpha.601",
6
+ "changes": [
7
+ "Mailbox tab loading hang: listMailOutbound now downloads blobs in parallel (MESSAGE_LIST_SCAN_CONCURRENCY=32) instead of sequentially, and accepts an optional limit. The Mailbox tab passes limit=50 so the UI no longer blocks on a full-history scan for agents with many outbound records."
8
+ ]
9
+ },
4
10
  {
5
11
  "version": "0.1.0-alpha.600",
6
12
  "changes": [
@@ -8,6 +8,10 @@ const reader_1 = require("../../../mailroom/reader");
8
8
  const core_1 = require("../../../mailroom/core");
9
9
  const MAILBOX_MAIL_LIST_LIMIT = 50;
10
10
  const MAILBOX_MAIL_SUMMARY_LIMIT = MAILBOX_MAIL_LIST_LIMIT;
11
+ // Cap the outbound list returned to the UI. The Mailbox tab renders a
12
+ // bounded recent-outbound view; surfacing the entire outbound history is
13
+ // what makes the tab hang on a loading spinner for large mailboxes.
14
+ const MAILBOX_MAIL_OUTBOUND_LIMIT = 50;
11
15
  const MAILBOX_MAIL_BODY_LIMIT = 12_000;
12
16
  function emptyFolders() {
13
17
  return [
@@ -272,7 +276,11 @@ async function readMailView(agentName) {
272
276
  const summaries = result.decrypted.map(mailSummary);
273
277
  const screener = (await resolved.store.listScreenerCandidates({ agentId: agentName, status: "pending", limit: 100 }))
274
278
  .map(screenerCandidate);
275
- const outbound = (await resolved.store.listMailOutbound(agentName)).map(outboundRecord);
279
+ // Cap outbound records returned to the UI. The mailbox tab shows a
280
+ // bounded recent-outbound view; pulling the entire history blocks the
281
+ // Mailbox tab on a loading spinner while the blob/file store grinds
282
+ // through every outbound record the agent has ever written.
283
+ const outbound = (await resolved.store.listMailOutbound(agentName, { limit: MAILBOX_MAIL_OUTBOUND_LIMIT })).map(outboundRecord);
276
284
  await resolved.store.recordAccess({
277
285
  agentId: agentName,
278
286
  tool: "mailbox_mail_list",
@@ -642,24 +642,36 @@ class AzureBlobMailroomStore {
642
642
  });
643
643
  return record;
644
644
  }
645
- async listMailOutbound(agentId) {
645
+ async listMailOutbound(agentId, options = {}) {
646
646
  await this.ensureContainer();
647
- const records = [];
647
+ // Stream blob NAMES first (no JSON downloads yet), then fan out the
648
+ // downloads with bounded concurrency. The previous loop awaited each
649
+ // download sequentially inside the iterator, which made every Mailbox
650
+ // tab open scale linearly with the total number of outbound records in
651
+ // the container — for an agent with many drafts/sent/failed entries,
652
+ // the UI sat on a loading spinner for minutes (or never finished) while
653
+ // the daemon ground through O(N) sequential network round-trips.
654
+ const outboundBlobNames = [];
648
655
  for await (const item of this.container.listBlobsFlat({ prefix: "outbound/" })) {
649
- const record = await downloadJson(this.container.getBlockBlobClient(item.name), this.blobOperationTimeoutMs);
650
- if (record)
651
- records.push(record);
656
+ outboundBlobNames.push(item.name);
652
657
  }
653
- const filtered = records
658
+ const downloaded = await mapWithConcurrency(outboundBlobNames, MESSAGE_LIST_SCAN_CONCURRENCY, async (name) => {
659
+ return downloadJson(this.container.getBlockBlobClient(name), this.blobOperationTimeoutMs);
660
+ });
661
+ const filtered = downloaded
662
+ .filter((record) => record !== null)
654
663
  .filter((record) => record.agentId === agentId)
655
664
  .sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
665
+ const limited = typeof options.limit === "number" && options.limit > 0
666
+ ? filtered.slice(0, options.limit)
667
+ : filtered;
656
668
  (0, runtime_1.emitNervesEvent)({
657
669
  component: "senses",
658
670
  event: "senses.mail_blob_outbound_records_listed",
659
671
  message: "azure blob mail outbound records listed",
660
- meta: { agentId, count: filtered.length },
672
+ meta: { agentId, count: limited.length, scanned: outboundBlobNames.length },
661
673
  });
662
- return filtered;
674
+ return limited;
663
675
  }
664
676
  async recordAccess(entry) {
665
677
  await this.ensureContainer();
@@ -327,20 +327,23 @@ class FileMailroomStore {
327
327
  });
328
328
  return record;
329
329
  }
330
- async listMailOutbound(agentId) {
330
+ async listMailOutbound(agentId, options = {}) {
331
331
  const records = fs.readdirSync(this.outboundDir)
332
332
  .filter((name) => name.endsWith(".json"))
333
333
  .map((name) => readJson(path.join(this.outboundDir, name)))
334
334
  .filter((record) => record !== null)
335
335
  .filter((record) => record.agentId === agentId)
336
336
  .sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
337
+ const limited = typeof options.limit === "number" && options.limit > 0
338
+ ? records.slice(0, options.limit)
339
+ : records;
337
340
  (0, runtime_1.emitNervesEvent)({
338
341
  component: "senses",
339
342
  event: "senses.mail_outbound_records_listed",
340
343
  message: "mail outbound records listed",
341
- meta: { agentId, count: records.length },
344
+ meta: { agentId, count: limited.length, scanned: records.length },
342
345
  });
343
- return records;
346
+ return limited;
344
347
  }
345
348
  async recordAccess(entry) {
346
349
  const complete = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.600",
3
+ "version": "0.1.0-alpha.601",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",