copilot-api-plus 1.2.48 → 1.2.50

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/main.js CHANGED
@@ -1728,6 +1728,168 @@ async function checkRateLimit(state) {
1728
1728
  }
1729
1729
  }
1730
1730
  //#endregion
1731
+ //#region src/routes/messages/strip-reminders.ts
1732
+ /** Matches `<system-reminder>…</system-reminder>` non-greedy, across lines. */
1733
+ const REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/g;
1734
+ /** Cheap sentinel that lets callers skip the regex scan. */
1735
+ const REMINDER_OPEN_TAG = "<system-reminder>";
1736
+ /**
1737
+ * Strip every `<system-reminder>` block from a plain string.
1738
+ *
1739
+ * Collapses runs of 3+ newlines left behind by the removal into a
1740
+ * single blank line, then trims leading/trailing whitespace. Returns
1741
+ * the same reference if no reminder was present (zero allocation).
1742
+ */
1743
+ function stripText(s) {
1744
+ if (!s.includes(REMINDER_OPEN_TAG)) return s;
1745
+ return s.replaceAll(REMINDER_RE, "").replaceAll(/\n{3,}/g, "\n\n").trim();
1746
+ }
1747
+ /**
1748
+ * Strip reminders from a block array. Non-text blocks pass through.
1749
+ * Text blocks that become empty after stripping are filtered out.
1750
+ * Returns the same reference if nothing changed.
1751
+ */
1752
+ function stripBlocks(content) {
1753
+ if (!content.some((b) => b.type === "text" && b.text.includes(REMINDER_OPEN_TAG) || b.type === "tool_result" && b.content.includes(REMINDER_OPEN_TAG))) return content;
1754
+ const out = [];
1755
+ for (const b of content) {
1756
+ if (b.type === "tool_result") {
1757
+ const orig = b.content;
1758
+ const stripped = stripText(orig);
1759
+ if (stripped === orig) out.push(b);
1760
+ else if (stripped.length === 0) out.push({
1761
+ ...b,
1762
+ content: " "
1763
+ });
1764
+ else out.push({
1765
+ ...b,
1766
+ content: stripped
1767
+ });
1768
+ continue;
1769
+ }
1770
+ if (b.type !== "text") {
1771
+ out.push(b);
1772
+ continue;
1773
+ }
1774
+ const t = stripText(b.text);
1775
+ if (t.length === 0) continue;
1776
+ out.push(t === b.text ? b : {
1777
+ ...b,
1778
+ text: t
1779
+ });
1780
+ }
1781
+ return out;
1782
+ }
1783
+ /**
1784
+ * Strip reminders from a single message. Returns the same reference
1785
+ * if nothing changed.
1786
+ */
1787
+ function stripMessage(message) {
1788
+ if (typeof message.content === "string") {
1789
+ const next = stripText(message.content);
1790
+ if (next === message.content) return message;
1791
+ return {
1792
+ ...message,
1793
+ content: next
1794
+ };
1795
+ }
1796
+ const next = stripBlocks(message.content);
1797
+ if (next === message.content) return message;
1798
+ return {
1799
+ ...message,
1800
+ content: next
1801
+ };
1802
+ }
1803
+ /**
1804
+ * Strip reminders from the `system` field (string OR text-block array).
1805
+ * Returns the same reference if nothing changed.
1806
+ */
1807
+ function stripSystem(system) {
1808
+ if (system === void 0) return system;
1809
+ if (typeof system === "string") {
1810
+ const next = stripText(system);
1811
+ return next === system ? system : next;
1812
+ }
1813
+ if (!system.some((b) => b.text.includes(REMINDER_OPEN_TAG))) return system;
1814
+ const out = [];
1815
+ for (const b of system) {
1816
+ const t = stripText(b.text);
1817
+ if (t.length === 0) continue;
1818
+ out.push(t === b.text ? b : {
1819
+ ...b,
1820
+ text: t
1821
+ });
1822
+ }
1823
+ return out;
1824
+ }
1825
+ /**
1826
+ * Return a shallow-cloned payload with `<system-reminder>` blocks
1827
+ * removed from every message's text content AND the system field.
1828
+ * The input payload is NOT mutated; if no reminders are present
1829
+ * anywhere, the original payload reference is returned unchanged.
1830
+ */
1831
+ function stripSystemReminders(payload) {
1832
+ let changed = false;
1833
+ const newSystem = stripSystem(payload.system);
1834
+ if (newSystem !== payload.system) changed = true;
1835
+ const newMessages = payload.messages.map((m) => {
1836
+ const next = stripMessage(m);
1837
+ if (next !== m) changed = true;
1838
+ return next;
1839
+ });
1840
+ if (!changed) return payload;
1841
+ return {
1842
+ ...payload,
1843
+ system: newSystem,
1844
+ messages: newMessages
1845
+ };
1846
+ }
1847
+ /**
1848
+ * Strip reminders from an OpenAI-style chat completions payload.
1849
+ * Walks every message's content (string OR ContentPart[]). Filters
1850
+ * out text parts that become empty. Returns the same reference if
1851
+ * nothing changed.
1852
+ */
1853
+ function stripOpenAIReminders(payload) {
1854
+ let changed = false;
1855
+ const newMessages = payload.messages.map((m) => {
1856
+ if (m.content === null) return m;
1857
+ if (typeof m.content === "string") {
1858
+ const next = stripText(m.content);
1859
+ if (next === m.content) return m;
1860
+ changed = true;
1861
+ return {
1862
+ ...m,
1863
+ content: next
1864
+ };
1865
+ }
1866
+ if (!m.content.some((p) => p.type === "text" && typeof p.text === "string" && p.text.includes(REMINDER_OPEN_TAG))) return m;
1867
+ const out = [];
1868
+ for (const p of m.content) {
1869
+ if (p.type !== "text" || typeof p.text !== "string") {
1870
+ out.push(p);
1871
+ continue;
1872
+ }
1873
+ const t = stripText(p.text);
1874
+ if (t.length === 0) continue;
1875
+ out.push(t === p.text ? p : {
1876
+ ...p,
1877
+ text: t
1878
+ });
1879
+ }
1880
+ changed = true;
1881
+ return {
1882
+ ...m,
1883
+ content: out
1884
+ };
1885
+ });
1886
+ if (!changed) return payload;
1887
+ return {
1888
+ ...payload,
1889
+ messages: newMessages
1890
+ };
1891
+ }
1892
+ //#endregion
1731
1893
  //#region src/services/copilot/create-chat-completions.ts
1732
1894
  /**
1733
1895
  * Timeout for the initial HTTP connection + headers (not the body/stream).
@@ -2097,6 +2259,10 @@ async function handleMultiAccountHttpError(error, account, retryContext) {
2097
2259
  case 429:
2098
2260
  accountManager.markAccountStatus(account.id, "rate_limited", "429 Rate limited");
2099
2261
  return null;
2262
+ case 408:
2263
+ consola.warn(`Account ${account.label}: 408 request timeout (network issue, not rotating)`);
2264
+ error.__nonAccountError = true;
2265
+ return null;
2100
2266
  default:
2101
2267
  if (error.response.status >= 500) {
2102
2268
  accountManager.markAccountStatus(account.id, "error", `HTTP ${error.response.status}`);
@@ -2117,6 +2283,7 @@ async function handleMultiAccountHttpError(error, account, retryContext) {
2117
2283
  async function createWithMultiAccount(payload) {
2118
2284
  const triedAccountIds = /* @__PURE__ */ new Set();
2119
2285
  let lastError;
2286
+ let networkRetried = false;
2120
2287
  for (let attempt = 0; attempt < 3; attempt++) {
2121
2288
  const account = accountManager.getActiveAccount();
2122
2289
  if (!account || triedAccountIds.has(account.id)) break;
@@ -2171,7 +2338,14 @@ async function createWithMultiAccount(payload) {
2171
2338
  if (error.__nonAccountError) throw error;
2172
2339
  } else {
2173
2340
  const errMsg = error.message || String(error);
2174
- consola.warn(`Account ${account.label}: network error (not rotating): ${errMsg}`);
2341
+ if (!networkRetried) {
2342
+ networkRetried = true;
2343
+ consola.warn(`Account ${account.label}: network error, resetting pool and retrying once: ${errMsg}`);
2344
+ resetAccountConnections(account.id);
2345
+ triedAccountIds.delete(account.id);
2346
+ continue;
2347
+ }
2348
+ consola.warn(`Account ${account.label}: network error after retry (giving up): ${errMsg}`);
2175
2349
  throw error;
2176
2350
  }
2177
2351
  consola.warn(`Account ${account.label} failed (attempt ${attempt + 1}), trying next...`);
@@ -2249,7 +2423,7 @@ async function handleCompletion$1(c) {
2249
2423
  await checkRateLimit(state);
2250
2424
  const rawPayload = await c.req.json();
2251
2425
  consola.debug("Request payload:", JSON.stringify(rawPayload).slice(-400));
2252
- const payload = applyMaxTokens(rawPayload);
2426
+ const payload = applyMaxTokens(stripOpenAIReminders(rawPayload));
2253
2427
  if (state.manualApprove) await awaitApproval();
2254
2428
  const response = await createChatCompletions(payload);
2255
2429
  if (isNonStreaming$1(response)) {
@@ -2760,84 +2934,6 @@ function getAnthropicToolUseBlocks(toolCalls) {
2760
2934
  }));
2761
2935
  }
2762
2936
  //#endregion
2763
- //#region src/routes/messages/strip-reminders.ts
2764
- /** Matches `<system-reminder>…</system-reminder>` non-greedy, across lines. */
2765
- const REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/g;
2766
- /** Cheap sentinel that lets callers skip the regex scan. */
2767
- const REMINDER_OPEN_TAG = "<system-reminder>";
2768
- /**
2769
- * Strip every `<system-reminder>` block from a plain string.
2770
- *
2771
- * Collapses runs of 3+ newlines left behind by the removal into a
2772
- * single blank line, then trims leading/trailing whitespace. Returns
2773
- * the same reference if no reminder was present (zero allocation).
2774
- */
2775
- function stripText(s) {
2776
- if (!s.includes(REMINDER_OPEN_TAG)) return s;
2777
- return s.replaceAll(REMINDER_RE, "").replaceAll(/\n{3,}/g, "\n\n").trim();
2778
- }
2779
- /**
2780
- * Strip reminders from a block array. Non-text blocks pass through.
2781
- * Text blocks that become empty after stripping are filtered out.
2782
- * Returns the same reference if nothing changed.
2783
- */
2784
- function stripBlocks(content) {
2785
- if (!content.some((b) => b.type === "text" && b.text.includes(REMINDER_OPEN_TAG))) return content;
2786
- const out = [];
2787
- for (const b of content) {
2788
- if (b.type !== "text") {
2789
- out.push(b);
2790
- continue;
2791
- }
2792
- const t = stripText(b.text);
2793
- if (t.length === 0) continue;
2794
- out.push(t === b.text ? b : {
2795
- ...b,
2796
- text: t
2797
- });
2798
- }
2799
- return out;
2800
- }
2801
- /**
2802
- * Strip reminders from a single message. Returns the same reference
2803
- * if nothing changed.
2804
- */
2805
- function stripMessage(message) {
2806
- if (typeof message.content === "string") {
2807
- const next = stripText(message.content);
2808
- if (next === message.content) return message;
2809
- return {
2810
- ...message,
2811
- content: next
2812
- };
2813
- }
2814
- const next = stripBlocks(message.content);
2815
- if (next === message.content) return message;
2816
- return {
2817
- ...message,
2818
- content: next
2819
- };
2820
- }
2821
- /**
2822
- * Return a shallow-cloned payload with `<system-reminder>` blocks
2823
- * removed from every message's text content. The input payload is
2824
- * NOT mutated; if no reminders are present anywhere, the original
2825
- * payload reference is returned unchanged (no allocation).
2826
- */
2827
- function stripSystemReminders(payload) {
2828
- let changed = false;
2829
- const newMessages = payload.messages.map((m) => {
2830
- const next = stripMessage(m);
2831
- if (next !== m) changed = true;
2832
- return next;
2833
- });
2834
- if (!changed) return payload;
2835
- return {
2836
- ...payload,
2837
- messages: newMessages
2838
- };
2839
- }
2840
- //#endregion
2841
2937
  //#region src/routes/messages/count-tokens-handler.ts
2842
2938
  /**
2843
2939
  * Handles token counting for Anthropic messages.