@yoooclaw/phone-notifications 1.11.4-beta.7 → 1.11.4

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
@@ -1459,14 +1459,28 @@ async function transcribeWithModelProxy(audioOssUrl, audioDurationMs, apiConfig,
1459
1459
  logger.info(
1460
1460
  `[asr-submit] \u63D0\u4EA4\u957F\u5F55\u97F3\u4EFB\u52A1: endpoint=${submitEndpoint}, body=${stringifyForLog(submitBody) ?? "{}"}`
1461
1461
  );
1462
- const res = await fetch(submitEndpoint, {
1463
- method: "POST",
1464
- headers: {
1465
- "Content-Type": "application/json",
1466
- "X-Api-Key-Id": apiKey
1467
- },
1468
- body: JSON.stringify(submitBody)
1469
- });
1462
+ let res;
1463
+ try {
1464
+ res = await fetchWithRetry(
1465
+ submitEndpoint,
1466
+ {
1467
+ method: "POST",
1468
+ headers: {
1469
+ "Content-Type": "application/json",
1470
+ "X-Api-Key-Id": apiKey
1471
+ },
1472
+ body: JSON.stringify(submitBody)
1473
+ },
1474
+ { logger, context: "asr-submit" }
1475
+ );
1476
+ } catch (err2) {
1477
+ const msg = err2?.message ?? String(err2);
1478
+ logger.error(`[asr-submit] \u63D0\u4EA4\u957F\u5F55\u97F3\u4EFB\u52A1\u7F51\u7EDC\u5F02\u5E38 (\u5DF2\u91CD\u8BD5): ${msg}`);
1479
+ return {
1480
+ ok: false,
1481
+ error: `Model Proxy ASR submit network error: ${msg}`
1482
+ };
1483
+ }
1470
1484
  if (!res.ok) {
1471
1485
  const errText = await res.text();
1472
1486
  logger.error(
@@ -1583,19 +1597,46 @@ async function pollLongRecordingTaskResult(params) {
1583
1597
  } = params;
1584
1598
  const queryBaseUrl = resolveModelProxyLongRecordingQueryTaskResultBaseUrl(apiConfig);
1585
1599
  let lastStatus;
1600
+ const pollIntervalMs = getPollIntervalMs();
1586
1601
  for (let attempt = 1; attempt <= DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS; attempt++) {
1587
1602
  const queryUrl = `${queryBaseUrl}/${encodeURIComponent(taskId)}`;
1588
- const res = await fetch(queryUrl, {
1589
- method: "GET",
1590
- headers: {
1591
- "X-Api-Key-Id": apiKey
1603
+ let res;
1604
+ try {
1605
+ res = await fetch(queryUrl, {
1606
+ method: "GET",
1607
+ headers: {
1608
+ "X-Api-Key-Id": apiKey
1609
+ }
1610
+ });
1611
+ } catch (err2) {
1612
+ const msg = err2?.message ?? String(err2);
1613
+ logger.warn(
1614
+ `[asr-query] \u957F\u5F55\u97F3\u4EFB\u52A1\u67E5\u8BE2\u7F51\u7EDC\u5F02\u5E38: taskId=${taskId}, attempt=${attempt}, error=${msg} \u2014 \u7B49\u5F85\u4E0B\u6B21\u8F6E\u8BE2`
1615
+ );
1616
+ if (attempt < DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS) {
1617
+ await sleep2(pollIntervalMs);
1618
+ continue;
1592
1619
  }
1593
- });
1620
+ return {
1621
+ ok: false,
1622
+ error: `Model Proxy ASR query network error: ${msg}`
1623
+ };
1624
+ }
1594
1625
  if (!res.ok) {
1595
- const errText = await res.text();
1596
- logger.error(
1597
- `[asr-query-response] \u957F\u5F55\u97F3\u4EFB\u52A1\u67E5\u8BE2\u5931\u8D25: taskId=${taskId}, attempt=${attempt}, status=${res.status}, body=${errText.slice(0, 500)}`
1598
- );
1626
+ const errText = await res.text().catch(() => "");
1627
+ if (isRetryableHttpStatus(res.status)) {
1628
+ logger.warn(
1629
+ `[asr-query] \u957F\u5F55\u97F3\u4EFB\u52A1\u67E5\u8BE2\u6682\u65F6\u5931\u8D25: taskId=${taskId}, attempt=${attempt}, status=${res.status}, body=${errText.slice(0, 200)} \u2014 \u7B49\u5F85\u4E0B\u6B21\u8F6E\u8BE2`
1630
+ );
1631
+ if (attempt < DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS) {
1632
+ await sleep2(pollIntervalMs);
1633
+ continue;
1634
+ }
1635
+ } else {
1636
+ logger.error(
1637
+ `[asr-query-response] \u957F\u5F55\u97F3\u4EFB\u52A1\u67E5\u8BE2\u5931\u8D25: taskId=${taskId}, attempt=${attempt}, status=${res.status}, body=${errText.slice(0, 500)}`
1638
+ );
1639
+ }
1599
1640
  return {
1600
1641
  ok: false,
1601
1642
  error: `Model Proxy ASR query error: ${res.status} ${errText.slice(0, 200)}`
@@ -1646,12 +1687,12 @@ async function pollLongRecordingTaskResult(params) {
1646
1687
  };
1647
1688
  }
1648
1689
  if (attempt < DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS) {
1649
- await sleep2(DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS);
1690
+ await sleep2(pollIntervalMs);
1650
1691
  }
1651
1692
  }
1652
1693
  return {
1653
1694
  ok: false,
1654
- error: `Model Proxy ASR \u8F6E\u8BE2\u8D85\u65F6: taskId=${taskId}, waited=${DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS * DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS}ms`
1695
+ error: `Model Proxy ASR \u8F6E\u8BE2\u8D85\u65F6: taskId=${taskId}, waited=${DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS * pollIntervalMs}ms`
1655
1696
  };
1656
1697
  }
1657
1698
  function buildLongRecordingSuccessResult(taskId, requestId, data, audioDurationMs, logger) {
@@ -1802,6 +1843,61 @@ function stringifyForLog(value, maxLength = 500) {
1802
1843
  async function sleep2(ms) {
1803
1844
  await new Promise((resolve) => setTimeout(resolve, ms));
1804
1845
  }
1846
+ function isRetryableHttpStatus(status) {
1847
+ return status === 429 || status >= 500;
1848
+ }
1849
+ function getHttpRetryBackoffMs() {
1850
+ const raw = process.env.OPENCLAW_ASR_HTTP_RETRY_BACKOFF_MS;
1851
+ if (raw) {
1852
+ const parsed = Number(raw);
1853
+ if (Number.isFinite(parsed) && parsed >= 0) {
1854
+ return parsed;
1855
+ }
1856
+ }
1857
+ return DEFAULT_HTTP_RETRY_BACKOFF_MS;
1858
+ }
1859
+ function getPollIntervalMs() {
1860
+ const raw = process.env.OPENCLAW_ASR_POLL_INTERVAL_MS;
1861
+ if (raw) {
1862
+ const parsed = Number(raw);
1863
+ if (Number.isFinite(parsed) && parsed >= 0) {
1864
+ return parsed;
1865
+ }
1866
+ }
1867
+ return DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS;
1868
+ }
1869
+ async function fetchWithRetry(url, init, options) {
1870
+ const maxAttempts = options.maxAttempts ?? DEFAULT_HTTP_MAX_ATTEMPTS;
1871
+ const baseBackoff = options.backoffMs ?? getHttpRetryBackoffMs();
1872
+ let lastError;
1873
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1874
+ try {
1875
+ const res = await fetch(url, init);
1876
+ if (isRetryableHttpStatus(res.status) && attempt < maxAttempts) {
1877
+ const errText = await res.text().catch(() => "");
1878
+ const delay = baseBackoff * Math.pow(2, attempt - 1);
1879
+ options.logger.warn(
1880
+ `[${options.context}] HTTP ${res.status} (attempt ${attempt}/${maxAttempts}), ${delay}ms \u540E\u91CD\u8BD5, body=${errText.slice(0, 200)}`
1881
+ );
1882
+ await sleep2(delay);
1883
+ continue;
1884
+ }
1885
+ return res;
1886
+ } catch (err2) {
1887
+ lastError = err2;
1888
+ if (attempt < maxAttempts) {
1889
+ const delay = baseBackoff * Math.pow(2, attempt - 1);
1890
+ const msg = err2?.message ?? String(err2);
1891
+ options.logger.warn(
1892
+ `[${options.context}] \u7F51\u7EDC\u5F02\u5E38 (attempt ${attempt}/${maxAttempts}): ${msg}, ${delay}ms \u540E\u91CD\u8BD5`
1893
+ );
1894
+ await sleep2(delay);
1895
+ continue;
1896
+ }
1897
+ }
1898
+ }
1899
+ throw lastError instanceof Error ? lastError : new Error(String(lastError));
1900
+ }
1805
1901
  function formatTimestamp(ms) {
1806
1902
  const totalSeconds = Math.floor(ms / 1e3);
1807
1903
  const minutes = Math.floor(totalSeconds / 60);
@@ -1830,7 +1926,7 @@ function formatTranscriptSegmentText(segment) {
1830
1926
  }
1831
1927
  return text;
1832
1928
  }
1833
- var import_node_fs25, import_node_path21, DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS, DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS, LONG_RECORDING_RUNNING_STATUSES, LONG_RECORDING_TERMINAL_FAILURE_STATUSES;
1929
+ var import_node_fs25, import_node_path21, DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS, DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS, LONG_RECORDING_RUNNING_STATUSES, LONG_RECORDING_TERMINAL_FAILURE_STATUSES, DEFAULT_HTTP_MAX_ATTEMPTS, DEFAULT_HTTP_RETRY_BACKOFF_MS;
1834
1930
  var init_asr = __esm({
1835
1931
  "src/recording/asr.ts"() {
1836
1932
  "use strict";
@@ -1843,6 +1939,8 @@ var init_asr = __esm({
1843
1939
  DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS = 3600;
1844
1940
  LONG_RECORDING_RUNNING_STATUSES = /* @__PURE__ */ new Set(["PENDING", "RUNNING", "SUSPENDED"]);
1845
1941
  LONG_RECORDING_TERMINAL_FAILURE_STATUSES = /* @__PURE__ */ new Set(["FAILED", "CANCELED", "UNKNOWN"]);
1942
+ DEFAULT_HTTP_MAX_ATTEMPTS = 3;
1943
+ DEFAULT_HTTP_RETRY_BACKOFF_MS = 2e3;
1846
1944
  }
1847
1945
  });
1848
1946
 
@@ -5480,7 +5578,7 @@ function readBuildInjectedVersion() {
5480
5578
  if (false) {
5481
5579
  return void 0;
5482
5580
  }
5483
- const version = "1.11.4-beta.7".trim();
5581
+ const version = "1.11.4".trim();
5484
5582
  return version || void 0;
5485
5583
  }
5486
5584
  function readPluginVersionFromPackageJson() {