@nanogpt/private-mode 0.2.5 → 0.2.7

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.md CHANGED
@@ -54,6 +54,7 @@ GET http://127.0.0.1:8787/v1/private-mode/attestation
54
54
 
55
55
  Supported private model IDs include:
56
56
 
57
+ - `private/deepseek-v4-flash`
57
58
  - `private/kimi-k3`
58
59
  - `private/glm-5-1`
59
60
  - `private/glm-5-1-thinking`
@@ -27,6 +27,9 @@ const KIMI_K3_AUDIO_URL_TOKENS = 4_096;
27
27
  const KIMI_K3_VIDEO_TOKENS = 65_536;
28
28
  const KIMI_K3_REASONING_EFFORT_LEVELS = new Set(['low', 'high', 'max']);
29
29
  const KIMI_K3_TEXT_ENCODER = new TextEncoder();
30
+ const DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS = 1_048_576;
31
+ const DEEPSEEK_V4_MAX_COMPLETION_TOKENS = 1_048_576;
32
+ const DEEPSEEK_V4_CONTEXT_SAFETY_MARGIN_TOKENS = 10;
30
33
  const PRIVATE_TINFOIL_CHAT_COMPLETION_BODY_FIELDS = new Set([
31
34
  'chat_template_kwargs',
32
35
  'frequency_penalty',
@@ -510,15 +513,18 @@ export function normalizePrivateModelReasoningControls(body, model) {
510
513
  }
511
514
 
512
515
  export function shouldSuppressPrivateModelReasoning(body, model) {
513
- if (!isPrivateModeKimiK3Model(model)) return false;
514
- return body.reasoningOptOut === true ||
516
+ const isKimiK3 = isPrivateModeKimiK3Model(model);
517
+ if (!isKimiK3 && model.thinkingMode !== 'deepseek-v4') return false;
518
+ const reasoningVisibilityOptOut = body.reasoningOptOut === true ||
515
519
  body.exposeReasoning === false ||
516
520
  body.materializeReasoning === false ||
517
521
  coercePrivateModeBooleanFlag(body.include_reasoning) === false ||
522
+ (isPlainObject(body.reasoning) && body.reasoning.exclude === true);
523
+ return reasoningVisibilityOptOut || (isKimiK3 &&
518
524
  [body.enable_thinking, body.thinking, body.reasoning_effort, body.reasoning]
519
525
  .some((value) => isKimiK3ReasoningOptOutCandidate(value) || (
520
526
  isPlainObject(value) && value.exclude === true
521
- ));
527
+ )));
522
528
  }
523
529
 
524
530
  function resolvePrivateModeKimiK3ReasoningEffort(body) {
@@ -580,6 +586,29 @@ function applyPrivateModeKimiK3RequestParams(body) {
580
586
  );
581
587
  }
582
588
 
589
+ function clampPrivateModeDeepSeekV4Output(body) {
590
+ const requestedMaxTokens = typeof body.max_tokens === 'number' && Number.isFinite(body.max_tokens)
591
+ ? body.max_tokens
592
+ : undefined;
593
+ if (requestedMaxTokens === undefined) return;
594
+
595
+ const normalizedMaxTokens = requestedMaxTokens < 0
596
+ ? DEEPSEEK_V4_MAX_COMPLETION_TOKENS
597
+ : requestedMaxTokens;
598
+ const promptTokenEstimate = estimatePrivateModeKimiK3PromptTokens(body);
599
+ const remainingContext = Math.max(
600
+ 1,
601
+ DEEPSEEK_V4_CONTEXT_WINDOW_TOKENS -
602
+ promptTokenEstimate -
603
+ DEEPSEEK_V4_CONTEXT_SAFETY_MARGIN_TOKENS,
604
+ );
605
+ body.max_tokens = Math.min(
606
+ Math.max(1, Math.floor(normalizedMaxTokens)),
607
+ DEEPSEEK_V4_MAX_COMPLETION_TOKENS,
608
+ remainingContext,
609
+ );
610
+ }
611
+
583
612
  export function createPrivateModeReasoningContentSuppressor() {
584
613
  const openTags = ['<think>', '<thinking>', '<previous_reasoning>', '◁think▷'];
585
614
  const closeTags = ['</think>', '</thinking>', '</previous_reasoning>', '◁/think▷'];
@@ -871,6 +900,8 @@ export function applyPrivateModelRequestMutations(body, model) {
871
900
  applyTinfoilCompatibilityMutations(body, model);
872
901
  if (isPrivateModeKimiK3Model(model)) {
873
902
  applyPrivateModeKimiK3RequestParams(body);
903
+ } else if (model.thinkingMode === 'deepseek-v4') {
904
+ clampPrivateModeDeepSeekV4Output(body);
874
905
  }
875
906
 
876
907
  if (model.thinkingMode === 'gemma') {
@@ -880,16 +911,21 @@ export function applyPrivateModelRequestMutations(body, model) {
880
911
  };
881
912
  delete body.thinking;
882
913
  delete body.reasoning_effort;
883
- } else if (model.thinkingMode === 'glm-5.2') {
914
+ } else if (
915
+ model.thinkingMode === 'glm-5.2' ||
916
+ model.thinkingMode === 'deepseek-v4'
917
+ ) {
884
918
  const thinkingEnabled = shouldEnableThinking(body, model);
919
+ const requestedReasoningEffort = body.reasoning_effort
920
+ ?? (isPlainObject(body.reasoning) ? body.reasoning.effort : undefined);
885
921
  body.chat_template_kwargs = {
886
922
  ...mergeChatTemplateKwargs(body),
887
923
  thinking: thinkingEnabled,
888
924
  };
889
925
 
890
- if (model.thinkingMode === 'glm-5.2' && thinkingEnabled) {
926
+ if (thinkingEnabled) {
891
927
  body.chat_template_kwargs.reasoning_effort =
892
- normalizeDeepSeekV4ReasoningEffort(body.reasoning_effort);
928
+ normalizeDeepSeekV4ReasoningEffort(requestedReasoningEffort);
893
929
  } else {
894
930
  delete body.chat_template_kwargs.reasoning_effort;
895
931
  }
package/lib/server.js CHANGED
@@ -183,8 +183,9 @@ async function runPreflight({ apiBase, apiKey, model, req, requestBodyBytes }) {
183
183
  try {
184
184
  const data = await response.json();
185
185
  const cacheScope = typeof data?.cacheScope === 'string' ? data.cacheScope.trim() : '';
186
- if (/^[a-f0-9]{64}$/i.test(cacheScope)) {
187
- return { ok: true, cacheScope };
186
+ const preflightTicket = typeof data?.preflightTicket === 'string' ? data.preflightTicket.trim() : '';
187
+ if (/^[a-f0-9]{64}$/i.test(cacheScope) && preflightTicket) {
188
+ return { ok: true, cacheScope, preflightTicket };
188
189
  }
189
190
  } catch {}
190
191
 
@@ -312,6 +313,7 @@ async function handleChatCompletion({ apiBase, apiKey, secureState, req, res, co
312
313
  'x-nanogpt-private-model': model.id,
313
314
  'x-nanogpt-private-stream': privateStreamRequested ? 'true' : 'false',
314
315
  'x-nanogpt-private-cache-scope': buildPrivateModeCacheScopeProof(preflight.cacheScope),
316
+ 'x-nanogpt-private-preflight-ticket': preflight.preflightTicket,
315
317
  'x-query-source': 'api',
316
318
  ...copyLocalHeaders(req),
317
319
  },
@@ -1,4 +1,16 @@
1
1
  [
2
+ {
3
+ "id": "private/deepseek-v4-flash",
4
+ "name": "DeepSeek V4 Flash Private",
5
+ "upstreamModel": "deepseek-v4-flash",
6
+ "billingModel": "private/deepseek-v4-flash",
7
+ "teeTargetModel": "deepseek-v4-flash",
8
+ "thinkingMode": "deepseek-v4",
9
+ "maxOutputTokens": 1048576,
10
+ "created": 1786406400,
11
+ "ownedBy": "nanogpt-private-mode",
12
+ "aliases": ["TEE/deepseek-v4-flash"]
13
+ },
2
14
  {
3
15
  "id": "private/kimi-k3",
4
16
  "name": "Kimi K3 Private",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanogpt/private-mode",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "OpenAI-compatible localhost proxy for NanoGPT Private Mode.",
5
5
  "type": "module",
6
6
  "publishConfig": {