copilot-api-plus 1.2.47 → 1.2.49
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/README.en.md +1 -0
- package/README.md +1 -0
- package/dist/main.js +163 -58
- package/dist/main.js.map +1 -1
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -51,6 +51,7 @@ English | [简体中文](README.md)
|
|
|
51
51
|
| ✂️ **Context Passthrough** | Full context passthrough to upstream API; clients (e.g. Claude Code) manage compression |
|
|
52
52
|
| 🔍 **Smart Model Matching** | Handles model name format differences (date suffixes, dash/dot versions, etc.) |
|
|
53
53
|
| 🧠 **Thinking Chain** | Automatically enables deep thinking for supported models, improving code quality |
|
|
54
|
+
| 🧹 **Reminder Stripping** | Strips client-injected reminder blocks before forwarding, avoiding upstream false-positive rejections |
|
|
54
55
|
|
|
55
56
|
---
|
|
56
57
|
|
package/README.md
CHANGED
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).
|
|
@@ -2249,7 +2411,7 @@ async function handleCompletion$1(c) {
|
|
|
2249
2411
|
await checkRateLimit(state);
|
|
2250
2412
|
const rawPayload = await c.req.json();
|
|
2251
2413
|
consola.debug("Request payload:", JSON.stringify(rawPayload).slice(-400));
|
|
2252
|
-
const payload = applyMaxTokens(rawPayload);
|
|
2414
|
+
const payload = applyMaxTokens(stripOpenAIReminders(rawPayload));
|
|
2253
2415
|
if (state.manualApprove) await awaitApproval();
|
|
2254
2416
|
const response = await createChatCompletions(payload);
|
|
2255
2417
|
if (isNonStreaming$1(response)) {
|
|
@@ -2760,63 +2922,6 @@ function getAnthropicToolUseBlocks(toolCalls) {
|
|
|
2760
2922
|
}));
|
|
2761
2923
|
}
|
|
2762
2924
|
//#endregion
|
|
2763
|
-
//#region src/routes/messages/strip-reminders.ts
|
|
2764
|
-
const REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/g;
|
|
2765
|
-
function stripFromText(text) {
|
|
2766
|
-
if (!text.includes("<system-reminder>")) return text;
|
|
2767
|
-
return text.replaceAll(REMINDER_RE, "").replaceAll(/\n{3,}/g, "\n\n").trim();
|
|
2768
|
-
}
|
|
2769
|
-
function stripFromBlock(block) {
|
|
2770
|
-
if (block.type !== "text") return block;
|
|
2771
|
-
const text = block.text;
|
|
2772
|
-
const stripped = stripFromText(text);
|
|
2773
|
-
if (stripped === text) return block;
|
|
2774
|
-
return {
|
|
2775
|
-
...block,
|
|
2776
|
-
text: stripped
|
|
2777
|
-
};
|
|
2778
|
-
}
|
|
2779
|
-
function stripFromMessage(message) {
|
|
2780
|
-
if (typeof message.content === "string") {
|
|
2781
|
-
const stripped = stripFromText(message.content);
|
|
2782
|
-
if (stripped === message.content) return message;
|
|
2783
|
-
return {
|
|
2784
|
-
...message,
|
|
2785
|
-
content: stripped
|
|
2786
|
-
};
|
|
2787
|
-
}
|
|
2788
|
-
let changed = false;
|
|
2789
|
-
const newBlocks = message.content.map((block) => {
|
|
2790
|
-
const next = stripFromBlock(block);
|
|
2791
|
-
if (next !== block) changed = true;
|
|
2792
|
-
return next;
|
|
2793
|
-
});
|
|
2794
|
-
if (!changed) return message;
|
|
2795
|
-
return {
|
|
2796
|
-
...message,
|
|
2797
|
-
content: newBlocks
|
|
2798
|
-
};
|
|
2799
|
-
}
|
|
2800
|
-
/**
|
|
2801
|
-
* Return a shallow-cloned payload with `<system-reminder>` blocks removed
|
|
2802
|
-
* from every message's text content. The input payload is NOT mutated.
|
|
2803
|
-
* If no reminders are present anywhere, the original payload is returned
|
|
2804
|
-
* unchanged (no allocation).
|
|
2805
|
-
*/
|
|
2806
|
-
function stripSystemReminders(payload) {
|
|
2807
|
-
let changed = false;
|
|
2808
|
-
const newMessages = payload.messages.map((m) => {
|
|
2809
|
-
const next = stripFromMessage(m);
|
|
2810
|
-
if (next !== m) changed = true;
|
|
2811
|
-
return next;
|
|
2812
|
-
});
|
|
2813
|
-
if (!changed) return payload;
|
|
2814
|
-
return {
|
|
2815
|
-
...payload,
|
|
2816
|
-
messages: newMessages
|
|
2817
|
-
};
|
|
2818
|
-
}
|
|
2819
|
-
//#endregion
|
|
2820
2925
|
//#region src/routes/messages/count-tokens-handler.ts
|
|
2821
2926
|
/**
|
|
2822
2927
|
* Handles token counting for Anthropic messages.
|