copilot-api-plus 1.2.46 → 1.2.48

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 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
@@ -52,6 +52,7 @@
52
52
  | ✂️ **上下文透传** | 全量透传上下文至上游 API,由客户端(如 Claude Code)自行管理压缩 |
53
53
  | 🔍 **智能模型匹配** | 自动处理模型名格式差异(日期后缀、dash/dot 版本号等) |
54
54
  | 🧠 **Thinking 思维链** | 自动为支持的模型启用深度思考,提升代码质量 |
55
+ | 🧹 **Reminder 剥离** | 自动剥离客户端注入的提醒块,避免上游误判拒绝服务 |
55
56
 
56
57
  ---
57
58
 
package/dist/main.js CHANGED
@@ -2760,6 +2760,84 @@ function getAnthropicToolUseBlocks(toolCalls) {
2760
2760
  }));
2761
2761
  }
2762
2762
  //#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
2763
2841
  //#region src/routes/messages/count-tokens-handler.ts
2764
2842
  /**
2765
2843
  * Handles token counting for Anthropic messages.
@@ -2772,7 +2850,7 @@ async function handleCountTokens(c) {
2772
2850
  try {
2773
2851
  const anthropicBeta = c.req.header("anthropic-beta");
2774
2852
  const anthropicPayload = await c.req.json();
2775
- const openAIPayload = translateToOpenAI(anthropicPayload);
2853
+ const openAIPayload = translateToOpenAI(stripSystemReminders(anthropicPayload));
2776
2854
  const translatedModelName = translateModelName(anthropicPayload.model);
2777
2855
  const selectedModel = findModel(translatedModelName) ?? findModel(anthropicPayload.model);
2778
2856
  if (!selectedModel) {
@@ -3086,7 +3164,7 @@ async function handleCompletion(c) {
3086
3164
  messages_count: anthropicPayload.messages.length,
3087
3165
  max_tokens: anthropicPayload.max_tokens
3088
3166
  });
3089
- const openAIPayload = translateToOpenAI(anthropicPayload);
3167
+ const openAIPayload = translateToOpenAI(stripSystemReminders(anthropicPayload));
3090
3168
  if (state.manualApprove) await awaitApproval();
3091
3169
  const response = await createChatCompletions(openAIPayload);
3092
3170
  if (isNonStreaming(response)) return c.json(translateToAnthropic(response));