@nanogpt/private-mode 0.2.13 → 0.2.14
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 +17 -0
- package/bin/nanogpt-private-mode.js +2 -0
- package/lib/requestTransforms.js +13 -7
- package/lib/transportTimeouts.js +28 -0
- package/models/private-tee.json +3 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -81,6 +81,23 @@ Supported private model IDs include:
|
|
|
81
81
|
|
|
82
82
|
Both GLM 5.2 variants are deployed with a 393,216-token total context limit, with prompt and output sharing that window. GLM 5.3 Private and GLM 5.3 Flash Private each have a 1,048,576-token total context limit and a 131,072-token output ceiling. Kimi K3 Private has a 256,000-token context limit. DeepSeek V4 Flash 0731 Private has a 1,048,576-token total context limit. The model-list extension `context_length` is the combined prompt-and-output window, while `max_output_tokens` is the output ceiling within that same window. These values are not additive.
|
|
83
83
|
|
|
84
|
+
### Thinking without leaving Private Mode
|
|
85
|
+
|
|
86
|
+
Keep the same private model ID when enabling thinking. For example:
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"model": "private/deepseek-v4-flash",
|
|
91
|
+
"messages": [{ "role": "user", "content": "What is 17 times 19?" }],
|
|
92
|
+
"reasoning_effort": "high",
|
|
93
|
+
"stream": true
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
DeepSeek V4 Flash uses the 0731 release and supports optional thinking. GLM 5.2 and Gemma 4 also support optional thinking. Use `thinking: true` or `enable_thinking: true` to enable it; `thinking: false` disables it for these optional-thinking models. Kimi K3, GLM 5.3, and GLM 5.3 Flash always generate reasoning. GLM 5.3 models accept `low`, `high`, or `max` effort. `reasoning: { "exclude": true }` controls response visibility and does not disable thinking.
|
|
98
|
+
|
|
99
|
+
Non-streaming reasoning requests may take more than five minutes. The CLI allows the encrypted request to wait for the hosted route's response, with a 30-minute transport limit. The hosted route stops non-streaming generation after at most 29 minutes to leave time before its platform deadline. Use `stream: true` for earlier output, and configure your API client's timeout to allow long generations. Upgrade the local proxy as well as the hosted service to receive both timeout fixes.
|
|
100
|
+
|
|
84
101
|
Browser requests are locked down by default. The proxy only accepts same-machine clients and rejects browser `Origin` headers that are not explicitly allowed, so a random website or LAN client cannot spend the local `NANOGPT_API_KEY` while the proxy is running. If a local browser app needs to call the proxy directly, allow that exact origin:
|
|
85
102
|
|
|
86
103
|
```bash
|
|
@@ -4,6 +4,7 @@ import { parseArgs } from 'node:util';
|
|
|
4
4
|
import { PRIVATE_MODE_PROXY_VERSION } from '../lib/packageInfo.js';
|
|
5
5
|
import { startPrivateModeProxy } from '../lib/server.js';
|
|
6
6
|
import { verifyPrivateModeReceiptCli } from '../lib/verifyReceipt.js';
|
|
7
|
+
import { installPrivateModeTransportTimeouts } from '../lib/transportTimeouts.js';
|
|
7
8
|
|
|
8
9
|
const { values, positionals } = parseArgs({
|
|
9
10
|
options: {
|
|
@@ -69,6 +70,7 @@ if (!apiKey) {
|
|
|
69
70
|
process.exit(1);
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
installPrivateModeTransportTimeouts(String(values['api-base']));
|
|
72
74
|
startPrivateModeProxy({
|
|
73
75
|
apiBase: String(values['api-base']),
|
|
74
76
|
apiKey,
|
package/lib/requestTransforms.js
CHANGED
|
@@ -271,8 +271,11 @@ function shouldEnableThinking(body, model) {
|
|
|
271
271
|
));
|
|
272
272
|
|
|
273
273
|
return explicitThinking
|
|
274
|
+
?? isThinkingEnabled(body.enable_thinking)
|
|
274
275
|
?? explicitReasoning
|
|
275
276
|
?? (body.reasoning_effort !== undefined ? reasoningEffort !== 'none' : undefined)
|
|
277
|
+
?? isThinkingEnabled(body.chat_template_kwargs?.thinking)
|
|
278
|
+
?? isThinkingEnabled(body.chat_template_kwargs?.enable_thinking)
|
|
276
279
|
?? hasThinkingSuffix;
|
|
277
280
|
}
|
|
278
281
|
|
|
@@ -526,7 +529,6 @@ export function normalizePrivateModelReasoningControls(body, model) {
|
|
|
526
529
|
|
|
527
530
|
export function shouldSuppressPrivateModelReasoning(body, model) {
|
|
528
531
|
const isKimiK3 = isPrivateModeKimiK3Model(model);
|
|
529
|
-
if (!isKimiK3 && model.thinkingMode !== 'deepseek-v4' && model.thinkingMode !== 'glm-5.3') return false;
|
|
530
532
|
const reasoningVisibilityOptOut = body.reasoningOptOut === true ||
|
|
531
533
|
body.exposeReasoning === false ||
|
|
532
534
|
body.materializeReasoning === false ||
|
|
@@ -1071,22 +1073,26 @@ export function applyPrivateModelRequestMutations(body, model) {
|
|
|
1071
1073
|
? true
|
|
1072
1074
|
: shouldEnableThinking(body, model);
|
|
1073
1075
|
const requestedReasoningEffort = body.reasoning_effort
|
|
1074
|
-
?? (isPlainObject(body.reasoning) ? body.reasoning.effort : undefined)
|
|
1076
|
+
?? (isPlainObject(body.reasoning) ? body.reasoning.effort : undefined)
|
|
1077
|
+
?? body.chat_template_kwargs?.reasoning_effort;
|
|
1075
1078
|
body.chat_template_kwargs = {
|
|
1076
1079
|
...mergeChatTemplateKwargs(body),
|
|
1077
1080
|
thinking: thinkingEnabled,
|
|
1078
1081
|
};
|
|
1079
1082
|
|
|
1080
|
-
if (
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1083
|
+
if (model.thinkingMode === 'glm-5.3') {
|
|
1084
|
+
// Match the native GLM API and the browser client: low/high/max belongs
|
|
1085
|
+
// at the top level, including on tool turns.
|
|
1086
|
+
body.reasoning_effort = normalizeGlm53ReasoningEffort(requestedReasoningEffort);
|
|
1087
|
+
delete body.chat_template_kwargs.reasoning_effort;
|
|
1088
|
+
} else if (thinkingEnabled) {
|
|
1089
|
+
body.chat_template_kwargs.reasoning_effort = normalizeDeepSeekV4ReasoningEffort(requestedReasoningEffort);
|
|
1084
1090
|
} else {
|
|
1085
1091
|
delete body.chat_template_kwargs.reasoning_effort;
|
|
1086
1092
|
}
|
|
1087
1093
|
|
|
1088
1094
|
delete body.thinking;
|
|
1089
|
-
delete body.reasoning_effort;
|
|
1095
|
+
if (model.thinkingMode !== 'glm-5.3') delete body.reasoning_effort;
|
|
1090
1096
|
}
|
|
1091
1097
|
|
|
1092
1098
|
stripUnsupportedPrivateTinfoilFields(body);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Agent, setGlobalDispatcher } from 'undici';
|
|
2
|
+
import { PRIVATE_MODE_STREAM_ROUTE_MAX_DURATION_MS } from './constants.js';
|
|
3
|
+
|
|
4
|
+
export class PrivateModeDispatcher extends Agent {
|
|
5
|
+
constructor(apiBase) {
|
|
6
|
+
super();
|
|
7
|
+
this.chatUrl = new URL(`${apiBase.replace(/\/+$/, '')}/api/v1/private/tinfoil/v1/chat/completions`);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
dispatch(options, handler) {
|
|
11
|
+
// EHBP calls native fetch after encryption, without retaining a custom
|
|
12
|
+
// dispatcher. Scope the CLI's override to its configured encrypted endpoint.
|
|
13
|
+
// Override dispatch options, not Agent defaults: fetch supplies its own
|
|
14
|
+
// five-minute timeout values on every dispatch.
|
|
15
|
+
if (String(options.origin) === this.chatUrl.origin && options.path === this.chatUrl.pathname) {
|
|
16
|
+
options = {
|
|
17
|
+
...options,
|
|
18
|
+
headersTimeout: PRIVATE_MODE_STREAM_ROUTE_MAX_DURATION_MS,
|
|
19
|
+
bodyTimeout: PRIVATE_MODE_STREAM_ROUTE_MAX_DURATION_MS,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return super.dispatch(options, handler);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function installPrivateModeTransportTimeouts(apiBase) {
|
|
27
|
+
setGlobalDispatcher(new PrivateModeDispatcher(apiBase));
|
|
28
|
+
}
|
package/models/private-tee.json
CHANGED
|
@@ -97,6 +97,9 @@
|
|
|
97
97
|
"billingModel": "TEE/glm-5.3-flash",
|
|
98
98
|
"providerPricingModel": "TEE/glm-5.3-flash",
|
|
99
99
|
"teeTargetModel": "glm-5-3-flash",
|
|
100
|
+
"teeTargetAliases": [
|
|
101
|
+
"glm5-3-flash"
|
|
102
|
+
],
|
|
100
103
|
"maxInputTokens": 1048576,
|
|
101
104
|
"maxOutputTokens": 131072,
|
|
102
105
|
"thinkingMode": "glm-5.3",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nanogpt/private-mode",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.14",
|
|
4
4
|
"description": "OpenAI-compatible localhost proxy for NanoGPT Private Mode.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"lib/serverErrorNormalization.js",
|
|
24
24
|
"lib/sseResponsePump.js",
|
|
25
25
|
"lib/statusContract.js",
|
|
26
|
+
"lib/transportTimeouts.js",
|
|
26
27
|
"lib/verifyReceipt.js",
|
|
27
28
|
"models",
|
|
28
29
|
"README.md"
|
|
@@ -32,7 +33,8 @@
|
|
|
32
33
|
},
|
|
33
34
|
"dependencies": {
|
|
34
35
|
"ai": "6.0.220",
|
|
35
|
-
"tinfoil": "1.1.12"
|
|
36
|
+
"tinfoil": "1.1.12",
|
|
37
|
+
"undici": "6.28.0"
|
|
36
38
|
},
|
|
37
39
|
"engines": {
|
|
38
40
|
"node": ">=22"
|