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 +176 -80
- package/dist/main.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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.
|