@mindstudio-ai/agent 0.1.107 → 0.1.108

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.
@@ -1392,9 +1392,83 @@ function isReadOnlySql(sql) {
1392
1392
  const head = sql.trimStart().slice(0, 8).toUpperCase();
1393
1393
  return head.startsWith("SELECT") || head.startsWith("PRAGMA") || head.startsWith("EXPLAIN");
1394
1394
  }
1395
- function getOrOpen(url) {
1396
- if (socket && socket.readyState === WS_OPEN) {
1397
- return Promise.resolve(socket);
1395
+ function clearPendingTimer(p) {
1396
+ if (p.timer !== null) {
1397
+ clearTimeout(p.timer);
1398
+ p.timer = null;
1399
+ }
1400
+ }
1401
+ function forget(self, id) {
1402
+ self.pending.delete(id);
1403
+ self.inbound.delete(id);
1404
+ if (self.retired && self.pending.size === 0) {
1405
+ try {
1406
+ self.ws.close();
1407
+ } catch {
1408
+ }
1409
+ }
1410
+ }
1411
+ function retire(self, reason) {
1412
+ if (self.retired) {
1413
+ return;
1414
+ }
1415
+ self.retired = true;
1416
+ if (conn === self) {
1417
+ conn = null;
1418
+ }
1419
+ try {
1420
+ console.warn(
1421
+ `[mindstudio] db: retiring WebSocket after ${reason}; next query reconnects.`
1422
+ );
1423
+ } catch {
1424
+ }
1425
+ if (self.pending.size === 0) {
1426
+ try {
1427
+ self.ws.close();
1428
+ } catch {
1429
+ }
1430
+ }
1431
+ }
1432
+ function armIdleTimer(self, id, p) {
1433
+ clearPendingTimer(p);
1434
+ p.timer = setTimeout(() => {
1435
+ forget(self, id);
1436
+ retire(self, "a reply went silent");
1437
+ p.reject(new DbWsTransportError("ws reply went silent", true));
1438
+ }, WS_IDLE_TIMEOUT_MS);
1439
+ }
1440
+ function deliver(self, msg) {
1441
+ const p = self.pending.get(msg.id);
1442
+ if (!p) {
1443
+ return;
1444
+ }
1445
+ clearPendingTimer(p);
1446
+ forget(self, msg.id);
1447
+ if (msg.error) {
1448
+ p.reject(
1449
+ new MindStudioError(
1450
+ `[db] ${msg.error.message || "Database query failed"}`,
1451
+ msg.error.code || "db_query_error",
1452
+ 400,
1453
+ msg.error
1454
+ )
1455
+ );
1456
+ } else {
1457
+ p.resolve(msg.results);
1458
+ }
1459
+ }
1460
+ function failTransport(self, id, err) {
1461
+ const p = self.pending.get(id);
1462
+ if (!p) {
1463
+ return;
1464
+ }
1465
+ clearPendingTimer(p);
1466
+ forget(self, id);
1467
+ p.reject(err);
1468
+ }
1469
+ function getOrOpen(url, token) {
1470
+ if (conn && !conn.retired && conn.ws.readyState === WS_OPEN) {
1471
+ return Promise.resolve(conn);
1398
1472
  }
1399
1473
  if (opening) {
1400
1474
  return opening;
@@ -1407,17 +1481,22 @@ function getOrOpen(url) {
1407
1481
  }
1408
1482
  opening = new Promise((resolve, reject) => {
1409
1483
  let ws;
1484
+ let self = null;
1410
1485
  const fail = (err) => {
1411
1486
  clearTimeout(openTimer);
1412
- if (socket === ws) {
1413
- socket = null;
1487
+ if (self) {
1488
+ self.retired = true;
1489
+ if (conn === self) {
1490
+ conn = null;
1491
+ }
1492
+ for (const [, p] of self.pending) {
1493
+ clearPendingTimer(p);
1494
+ p.reject(new DbWsTransportError(err.message, true));
1495
+ }
1496
+ self.pending.clear();
1497
+ self.inbound.clear();
1414
1498
  }
1415
1499
  opening = null;
1416
- for (const [, p] of pending) {
1417
- clearTimeout(p.timer);
1418
- p.reject(new DbWsTransportError(err.message, true));
1419
- }
1420
- pending.clear();
1421
1500
  reject(err);
1422
1501
  };
1423
1502
  const openTimer = setTimeout(() => {
@@ -1428,16 +1507,26 @@ function getOrOpen(url) {
1428
1507
  fail(new DbWsTransportError("ws open timed out"));
1429
1508
  }, WS_OPEN_TIMEOUT_MS);
1430
1509
  try {
1431
- ws = new WebSocketCtor(url);
1510
+ ws = new WebSocketCtor(url, ["auth", token, DB_WS_SUBPROTOCOL]);
1432
1511
  } catch (err) {
1433
1512
  fail(new DbWsTransportError(err?.message || "ws construct failed"));
1434
1513
  return;
1435
1514
  }
1515
+ self = {
1516
+ ws,
1517
+ pending: /* @__PURE__ */ new Map(),
1518
+ chunked: false,
1519
+ inbound: /* @__PURE__ */ new Map(),
1520
+ acksSeen: false,
1521
+ retired: false
1522
+ };
1523
+ const c = self;
1436
1524
  ws.onopen = () => {
1437
1525
  clearTimeout(openTimer);
1438
- socket = ws;
1526
+ c.chunked = ws.protocol === DB_WS_SUBPROTOCOL;
1527
+ conn = c;
1439
1528
  opening = null;
1440
- resolve(ws);
1529
+ resolve(c);
1441
1530
  };
1442
1531
  ws.onmessage = (ev) => {
1443
1532
  let msg;
@@ -1448,26 +1537,54 @@ function getOrOpen(url) {
1448
1537
  } catch {
1449
1538
  return;
1450
1539
  }
1451
- if (!msg || msg.t !== "db-result" || msg.id == null) {
1540
+ if (!msg || msg.id == null) {
1452
1541
  return;
1453
1542
  }
1454
- const p = pending.get(msg.id);
1455
- if (!p) {
1543
+ if (msg.t === "db-ack") {
1544
+ c.acksSeen = true;
1545
+ const p = c.pending.get(msg.id);
1546
+ if (p && !p.acked) {
1547
+ p.acked = true;
1548
+ armIdleTimer(c, msg.id, p);
1549
+ }
1456
1550
  return;
1457
1551
  }
1458
- clearTimeout(p.timer);
1459
- pending.delete(msg.id);
1460
- if (msg.error) {
1461
- p.reject(
1462
- new MindStudioError(
1463
- `[db] ${msg.error.message || "Database query failed"}`,
1464
- msg.error.code || "db_query_error",
1465
- 400,
1466
- msg.error
1467
- )
1468
- );
1469
- } else {
1470
- p.resolve(msg.results);
1552
+ if (msg.t === "db-chunk") {
1553
+ const p = c.pending.get(msg.id);
1554
+ if (!p || typeof msg.data !== "string") {
1555
+ return;
1556
+ }
1557
+ const parts = c.inbound.get(msg.id);
1558
+ if (parts) {
1559
+ parts.push(msg.data);
1560
+ } else {
1561
+ c.inbound.set(msg.id, [msg.data]);
1562
+ }
1563
+ armIdleTimer(c, msg.id, p);
1564
+ return;
1565
+ }
1566
+ if (msg.t === "db-end") {
1567
+ const parts = c.inbound.get(msg.id);
1568
+ if (!parts) {
1569
+ return;
1570
+ }
1571
+ c.inbound.delete(msg.id);
1572
+ let assembled;
1573
+ try {
1574
+ assembled = JSON.parse(parts.join(""));
1575
+ } catch {
1576
+ failTransport(
1577
+ c,
1578
+ msg.id,
1579
+ new DbWsTransportError("chunked reply did not parse", true)
1580
+ );
1581
+ return;
1582
+ }
1583
+ deliver(c, assembled);
1584
+ return;
1585
+ }
1586
+ if (msg.t === "db-result") {
1587
+ deliver(c, msg);
1471
1588
  }
1472
1589
  };
1473
1590
  ws.onerror = () => fail(new DbWsTransportError("ws error"));
@@ -1475,41 +1592,75 @@ function getOrOpen(url) {
1475
1592
  });
1476
1593
  return opening;
1477
1594
  }
1595
+ function* outboundFrames(id, json) {
1596
+ if (json.length <= WS_CHUNK_CHARS) {
1597
+ yield json;
1598
+ return;
1599
+ }
1600
+ let seq = 0;
1601
+ for (let offset = 0; offset < json.length; offset += WS_CHUNK_CHARS) {
1602
+ yield JSON.stringify({
1603
+ t: "db-chunk",
1604
+ id,
1605
+ seq: seq++,
1606
+ data: json.slice(offset, offset + WS_CHUNK_CHARS)
1607
+ });
1608
+ }
1609
+ yield JSON.stringify({ t: "db-end", id });
1610
+ }
1478
1611
  async function executeDbBatchOverWs(url, token, databaseId, queries) {
1479
1612
  const id = ++idCounter;
1480
1613
  const frame = JSON.stringify({ t: "db", id, token, databaseId, queries });
1481
- if (frame.length > WS_MAX_FRAME_CHARS) {
1614
+ const self = await getOrOpen(url, token);
1615
+ if (!self.chunked && frame.length > WS_MAX_FRAME_CHARS) {
1482
1616
  throw new DbWsTransportError("payload too large for ws");
1483
1617
  }
1484
- const ws = await getOrOpen(url);
1485
1618
  return await new Promise((resolve, reject) => {
1486
- const timer = setTimeout(() => {
1487
- pending.delete(id);
1488
- reject(new DbWsTransportError("ws execute timed out", true));
1489
- }, WS_REQUEST_TIMEOUT_MS);
1490
- pending.set(id, { resolve, reject, timer });
1619
+ const pending = { resolve, reject, timer: null, acked: false };
1620
+ if (self.acksSeen) {
1621
+ pending.timer = setTimeout(() => {
1622
+ forget(self, id);
1623
+ retire(self, "a request went unacknowledged");
1624
+ reject(new DbWsTransportError("ws ack timed out", true));
1625
+ }, WS_ACK_TIMEOUT_MS);
1626
+ } else {
1627
+ armIdleTimer(self, id, pending);
1628
+ }
1629
+ self.pending.set(id, pending);
1630
+ let started = false;
1631
+ let complete = false;
1491
1632
  try {
1492
- ws.send(frame);
1633
+ for (const out of outboundFrames(id, frame)) {
1634
+ self.ws.send(out);
1635
+ started = true;
1636
+ }
1637
+ complete = true;
1493
1638
  } catch (err) {
1494
- clearTimeout(timer);
1495
- pending.delete(id);
1639
+ clearPendingTimer(pending);
1640
+ forget(self, id);
1641
+ if (started) {
1642
+ retire(self, "a partial request upload failed");
1643
+ }
1496
1644
  reject(
1497
1645
  new DbWsTransportError(
1498
1646
  `ws send failed: ${err?.message || "unknown"}`,
1499
- false
1647
+ complete
1500
1648
  )
1501
1649
  );
1502
1650
  }
1503
1651
  });
1504
1652
  }
1505
- var WS_REQUEST_TIMEOUT_MS, WS_OPEN_TIMEOUT_MS, WS_OPEN, WS_MAX_FRAME_CHARS, DbWsTransportError, socket, opening, idCounter, pending;
1653
+ var DB_WS_SUBPROTOCOL, WS_ACK_TIMEOUT_MS, WS_IDLE_TIMEOUT_MS, WS_OPEN_TIMEOUT_MS, WS_OPEN, WS_CHUNK_CHARS, WS_MAX_FRAME_CHARS, DbWsTransportError, conn, opening, idCounter;
1506
1654
  var init_db_ws = __esm({
1507
1655
  "src/db-ws.ts"() {
1508
1656
  "use strict";
1509
1657
  init_errors();
1510
- WS_REQUEST_TIMEOUT_MS = 3e5;
1658
+ DB_WS_SUBPROTOCOL = "ms-db-v2";
1659
+ WS_ACK_TIMEOUT_MS = 2e4;
1660
+ WS_IDLE_TIMEOUT_MS = 3e5;
1511
1661
  WS_OPEN_TIMEOUT_MS = 5e3;
1512
1662
  WS_OPEN = 1;
1663
+ WS_CHUNK_CHARS = 256 * 1024;
1513
1664
  WS_MAX_FRAME_CHARS = 9e5;
1514
1665
  DbWsTransportError = class extends Error {
1515
1666
  constructor(message, sent = false) {
@@ -1518,10 +1669,9 @@ var init_db_ws = __esm({
1518
1669
  }
1519
1670
  name = "DbWsTransportError";
1520
1671
  };
1521
- socket = null;
1672
+ conn = null;
1522
1673
  opening = null;
1523
1674
  idCounter = 0;
1524
- pending = /* @__PURE__ */ new Map();
1525
1675
  }
1526
1676
  });
1527
1677
 
@@ -4248,6 +4398,56 @@ var init_analytics = __esm({
4248
4398
  }
4249
4399
  });
4250
4400
 
4401
+ // src/email/index.ts
4402
+ function createEmail(call) {
4403
+ return {
4404
+ stats(options) {
4405
+ return call("stats", {
4406
+ start: iso(options?.start),
4407
+ end: iso(options?.end),
4408
+ buckets: options?.buckets
4409
+ });
4410
+ },
4411
+ messages(options) {
4412
+ return call("messages", {
4413
+ ...options,
4414
+ start: iso(options?.start),
4415
+ end: iso(options?.end)
4416
+ });
4417
+ },
4418
+ message(messageId) {
4419
+ return call("message", { messageId });
4420
+ },
4421
+ batches(options) {
4422
+ return call("batches", {
4423
+ start: iso(options?.start),
4424
+ end: iso(options?.end),
4425
+ limit: options?.limit,
4426
+ offset: options?.offset
4427
+ });
4428
+ },
4429
+ batch(batchId) {
4430
+ return call("batch", { batchId });
4431
+ },
4432
+ suppressions(options) {
4433
+ return call("suppressions", options ?? {});
4434
+ },
4435
+ suppress(email) {
4436
+ return call("suppress", { email });
4437
+ },
4438
+ unsuppress(email) {
4439
+ return call("unsuppress", { email });
4440
+ }
4441
+ };
4442
+ }
4443
+ var iso;
4444
+ var init_email = __esm({
4445
+ "src/email/index.ts"() {
4446
+ "use strict";
4447
+ iso = (v) => v === void 0 ? void 0 : v instanceof Date ? v.toISOString() : v;
4448
+ }
4449
+ });
4450
+
4251
4451
  // src/task/schema.ts
4252
4452
  function describe(value) {
4253
4453
  if (value === void 0) return "undefined";
@@ -5752,6 +5952,7 @@ var init_client = __esm({
5752
5952
  init_datasources();
5753
5953
  init_voice();
5754
5954
  init_analytics();
5955
+ init_email();
5755
5956
  await init_task();
5756
5957
  await init_local();
5757
5958
  init_schema();
@@ -5795,6 +5996,7 @@ var init_client = __esm({
5795
5996
  _dataSources;
5796
5997
  _voice;
5797
5998
  _analytics;
5999
+ _email;
5798
6000
  /** @internal Auth type — 'internal' for CALLBACK_TOKEN (managed mode), 'apiKey' otherwise. */
5799
6001
  _authType;
5800
6002
  /** @internal Usage source sent on step executions (from MINDSTUDIO_REQUEST_SOURCE).
@@ -6839,6 +7041,24 @@ var init_client = __esm({
6839
7041
  this._analyticsRequest.bind(this)
6840
7042
  );
6841
7043
  }
7044
+ /**
7045
+ * Outbound email: the per-recipient delivery log, blast stats, and this app's
7046
+ * unsubscribe list. Sending is the `sendEmail` action, not this namespace.
7047
+ *
7048
+ * @example
7049
+ * ```ts
7050
+ * import { email } from '@mindstudio-ai/agent';
7051
+ *
7052
+ * // A support lookup: did this person get their mail?
7053
+ * const { messages } = await email.messages({ recipient: 'a@b.com' });
7054
+ *
7055
+ * // How did the August newsletter do?
7056
+ * const blast = await email.batch('newsletter-2026-08');
7057
+ * ```
7058
+ */
7059
+ get email() {
7060
+ return this._email ??= createEmail(this._emailRequest.bind(this));
7061
+ }
6842
7062
  /**
6843
7063
  * Jewel surfaces: arrival-shaped triggers (`propose`) and the app-native
6844
7064
  * approval queue (`queue.list` / `queue.resolve`). See {@link JewelsApi}.
@@ -6977,6 +7197,18 @@ var init_client = __esm({
6977
7197
  * of surfacing as empty data. Deliberately single-shot and scoped to this
6978
7198
  * namespace — the other brokered transports keep their semantics.
6979
7199
  */
7200
+ /**
7201
+ * Brokered email transport. No 429 retry, unlike analytics: this namespace
7202
+ * carries writes (suppress / unsuppress), and silently retrying a mutation is a
7203
+ * different risk from retrying an idempotent read. A caller that wants one can
7204
+ * retry a read itself.
7205
+ */
7206
+ async _emailRequest(op, body) {
7207
+ return this._brokeredRequest("email", op, body, {
7208
+ fallbackMessage: "Email API call failed",
7209
+ fallbackCode: "email_error"
7210
+ });
7211
+ }
6980
7212
  async _analyticsRequest(op, body) {
6981
7213
  const call = () => this._brokeredRequest("analytics", op, body, {
6982
7214
  fallbackMessage: "Analytics read failed",
@@ -8295,7 +8527,7 @@ async function cmdAsk(question, options) {
8295
8527
  process.exit(1);
8296
8528
  }
8297
8529
  }
8298
- var DEFAULT_BASE_URL2, ansi;
8530
+ var DEFAULT_BASE_URL2, color, ansi;
8299
8531
  var init_ask = __esm({
8300
8532
  async "src/ask/index.ts"() {
8301
8533
  "use strict";
@@ -8305,12 +8537,11 @@ var init_ask = __esm({
8305
8537
  init_tools();
8306
8538
  init_prompt();
8307
8539
  DEFAULT_BASE_URL2 = "https://v1.mindstudio-api.com";
8540
+ color = process.stderr.isTTY;
8308
8541
  ansi = {
8309
- dim: (s) => `\x1B[2m${s}\x1B[0m`,
8310
- green: (s) => `\x1B[32m${s}\x1B[0m`,
8311
- red: (s) => `\x1B[31m${s}\x1B[0m`,
8312
- cyan: (s) => `\x1B[36m${s}\x1B[0m`,
8313
- bold: (s) => `\x1B[1m${s}\x1B[0m`
8542
+ dim: (s) => color ? `\x1B[2m${s}\x1B[0m` : s,
8543
+ cyan: (s) => color ? `\x1B[36m${s}\x1B[0m` : s,
8544
+ bold: (s) => color ? `\x1B[1m${s}\x1B[0m` : s
8314
8545
  };
8315
8546
  }
8316
8547
  });
@@ -8375,7 +8606,7 @@ async function startMcpServer(options) {
8375
8606
  capabilities: { tools: {} },
8376
8607
  serverInfo: {
8377
8608
  name: "mindstudio-agent",
8378
- version: "0.1.107"
8609
+ version: "0.1.108"
8379
8610
  },
8380
8611
  instructions: 'Welcome to MindStudio \u2014 a platform with 200+ AI models, 850+ third-party integrations, and pre-built agents.\n\nGetting started:\n1. Call `ask` with any question about the SDK \u2014 it knows every action, model, and connector and returns working code with real model IDs and config options. Examples: ask("generate an image with FLUX"), ask("what models support vision?"), ask("how do I send a Slack message?").\n2. Call `changeName` to set your display name \u2014 use your name or whatever your user calls you. This is how you\'ll appear in MindStudio request logs.\n3. If you have a profile picture, pass its public image URL to `changeProfilePicture`.\n4. For manual browsing, call `listActions` to discover all available actions.\n\nThen use the tools to generate text, images, video, audio, search the web, work with data sources, run agents, and more.\n\nImportant:\n- AI-powered actions (text generation, image generation, video, audio, etc.) cost money. Before running these, call `estimateActionCost` and confirm with the user before proceeding \u2014 unless they\'ve explicitly told you to go ahead.\n- Not all agents from `listAgents` are configured for API use. Do not try to run an agent just because it appears in the list \u2014 it will likely fail. Only run agents the user specifically asks you to run.'
8381
8612
  });
@@ -9263,7 +9494,7 @@ function isNewerVersion(current, latest) {
9263
9494
  return false;
9264
9495
  }
9265
9496
  async function checkForUpdate() {
9266
- const currentVersion = "0.1.107";
9497
+ const currentVersion = "0.1.108";
9267
9498
  if (!currentVersion) return null;
9268
9499
  try {
9269
9500
  const { loadConfig: loadConfig2, saveConfig: saveConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
@@ -9292,7 +9523,7 @@ async function checkForUpdate() {
9292
9523
  }
9293
9524
  }
9294
9525
  function printUpdateNotice(latestVersion) {
9295
- const currentVersion = "0.1.107";
9526
+ const currentVersion = "0.1.108";
9296
9527
  process.stderr.write(
9297
9528
  `
9298
9529
  ${ansi2.cyanBright("Update available")} ${ansi2.gray(currentVersion + " \u2192")} ${ansi2.cyanBold(latestVersion)}
@@ -9305,7 +9536,7 @@ function isStandaloneBinary() {
9305
9536
  return !argv1.includes("node_modules");
9306
9537
  }
9307
9538
  async function cmdUpdate() {
9308
- const currentVersion = "0.1.107";
9539
+ const currentVersion = "0.1.108";
9309
9540
  process.stderr.write(
9310
9541
  ` ${ansi2.gray("Current version:")} ${currentVersion}
9311
9542
  `
@@ -9420,7 +9651,7 @@ async function cmdLogin(options) {
9420
9651
  process.stderr.write("\n");
9421
9652
  printLogo();
9422
9653
  process.stderr.write("\n");
9423
- const ver = "0.1.107";
9654
+ const ver = "0.1.108";
9424
9655
  process.stderr.write(
9425
9656
  ` ${ansi2.bold("MindStudio Agent")} ${ver ? " " + ansi2.gray("v" + ver) : ""}
9426
9657
  `
@@ -9731,7 +9962,7 @@ async function main() {
9731
9962
  try {
9732
9963
  if (command === "version" || command === "-v") {
9733
9964
  process.stdout.write(
9734
- "0.1.107\n"
9965
+ "0.1.108\n"
9735
9966
  );
9736
9967
  return;
9737
9968
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindstudio-ai/agent",
3
- "version": "0.1.107",
3
+ "version": "0.1.108",
4
4
  "description": "TypeScript SDK for MindStudio direct step execution",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",