nvicode 0.1.18 → 0.1.20
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 +3 -1
- package/dist/cli.js +66 -23
- package/dist/config.js +7 -1
- package/dist/models.js +108 -5
- package/dist/proxy.js +33 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Nvicode - Free unlimited claudecode 40RPM
|
|
2
2
|
|
|
3
3
|
[](https://github.com/dineshpotla/nvicode/actions/workflows/ci.yml)
|
|
4
4
|
[](https://www.npmjs.com/package/nvicode)
|
|
@@ -17,6 +17,7 @@ What it gives you:
|
|
|
17
17
|
- OpenClaw support
|
|
18
18
|
- NVIDIA proxy mode with pacing and local usage tracking
|
|
19
19
|
- OpenRouter direct mode for compatible models
|
|
20
|
+
- Dynamic NVIDIA model discovery for current Kimi, DeepSeek, GLM, and Qwen picks
|
|
20
21
|
|
|
21
22
|
Supported environments:
|
|
22
23
|
- macOS
|
|
@@ -116,6 +117,7 @@ nvicode launch codex "Explain this project"
|
|
|
116
117
|
|
|
117
118
|
Behavior notes:
|
|
118
119
|
- `nvicode select model` asks for provider, optional API key update, and model choice in one guided flow.
|
|
120
|
+
- For NVIDIA, model selection fetches the live NVIDIA catalog and highlights one current top pick each from Kimi, DeepSeek, GLM, and Qwen before falling back to curated defaults.
|
|
119
121
|
- Claude Code uses direct OpenRouter mode for OpenRouter, and proxy mode for NVIDIA.
|
|
120
122
|
- Codex currently uses the local `nvicode` proxy path.
|
|
121
123
|
- `nvicode usage`, `activity`, and `dashboard` are currently focused on NVIDIA proxy sessions.
|
package/dist/cli.js
CHANGED
|
@@ -448,11 +448,19 @@ const runDashboard = async () => {
|
|
|
448
448
|
console.log("");
|
|
449
449
|
await runActivity();
|
|
450
450
|
};
|
|
451
|
-
const
|
|
451
|
+
const PROXY_PROTOCOL_VERSION = 2;
|
|
452
|
+
const isExpectedProxyHealth = (config, health) => health.ok === true &&
|
|
453
|
+
health.proxyProtocolVersion === PROXY_PROTOCOL_VERSION &&
|
|
454
|
+
health.provider === config.provider &&
|
|
455
|
+
health.model === getActiveModel(config) &&
|
|
456
|
+
health.port === config.proxyPort &&
|
|
457
|
+
health.thinking === config.thinking &&
|
|
458
|
+
health.maxRequestsPerMinute === config.maxRequestsPerMinute;
|
|
459
|
+
const waitForHealthyProxy = async (config) => {
|
|
452
460
|
for (let attempt = 0; attempt < 50; attempt += 1) {
|
|
453
461
|
try {
|
|
454
|
-
const response = await fetch(`http://127.0.0.1:${
|
|
455
|
-
if (response.ok) {
|
|
462
|
+
const response = await fetch(`http://127.0.0.1:${config.proxyPort}/health`);
|
|
463
|
+
if (response.ok && isExpectedProxyHealth(config, await response.json())) {
|
|
456
464
|
return true;
|
|
457
465
|
}
|
|
458
466
|
}
|
|
@@ -463,11 +471,35 @@ const waitForHealthyProxy = async (port) => {
|
|
|
463
471
|
}
|
|
464
472
|
return false;
|
|
465
473
|
};
|
|
474
|
+
const stopExistingProxy = async () => {
|
|
475
|
+
const paths = getNvicodePaths();
|
|
476
|
+
const rawPid = await readIfExists(paths.pidFile);
|
|
477
|
+
const pid = Number(rawPid?.trim());
|
|
478
|
+
if (!Number.isInteger(pid) || pid <= 0) {
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
try {
|
|
482
|
+
process.kill(pid, "SIGTERM");
|
|
483
|
+
}
|
|
484
|
+
catch {
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
for (let attempt = 0; attempt < 20; attempt += 1) {
|
|
488
|
+
try {
|
|
489
|
+
process.kill(pid, 0);
|
|
490
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
491
|
+
}
|
|
492
|
+
catch {
|
|
493
|
+
break;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
};
|
|
466
497
|
const ensureProxyRunning = async (config) => {
|
|
467
|
-
if (await waitForHealthyProxy(config
|
|
498
|
+
if (await waitForHealthyProxy(config)) {
|
|
468
499
|
return;
|
|
469
500
|
}
|
|
470
501
|
const paths = getNvicodePaths();
|
|
502
|
+
await stopExistingProxy();
|
|
471
503
|
await fs.mkdir(paths.stateDir, { recursive: true });
|
|
472
504
|
const logFd = openSync(paths.logFile, "a");
|
|
473
505
|
const child = spawn(process.execPath, [__filename, "serve"], {
|
|
@@ -480,7 +512,7 @@ const ensureProxyRunning = async (config) => {
|
|
|
480
512
|
});
|
|
481
513
|
child.unref();
|
|
482
514
|
await fs.writeFile(paths.pidFile, `${child.pid}\n`);
|
|
483
|
-
if (!(await waitForHealthyProxy(config
|
|
515
|
+
if (!(await waitForHealthyProxy(config))) {
|
|
484
516
|
throw new Error(`nvicode proxy failed to start. See ${paths.logFile}`);
|
|
485
517
|
}
|
|
486
518
|
};
|
|
@@ -536,6 +568,30 @@ const resolvePersistentClaudeCommand = async () => {
|
|
|
536
568
|
}
|
|
537
569
|
return null;
|
|
538
570
|
};
|
|
571
|
+
const resolveLatestClaudeManagedVersion = async () => {
|
|
572
|
+
const versionsDir = path.join(os.homedir(), ".local", "share", "claude", "versions");
|
|
573
|
+
try {
|
|
574
|
+
const entries = await fs.readdir(versionsDir);
|
|
575
|
+
const sortedEntries = entries.sort((left, right) => left.localeCompare(right, undefined, {
|
|
576
|
+
numeric: true,
|
|
577
|
+
sensitivity: "base",
|
|
578
|
+
}));
|
|
579
|
+
for (let index = sortedEntries.length - 1; index >= 0; index -= 1) {
|
|
580
|
+
const entry = sortedEntries[index];
|
|
581
|
+
if (!entry) {
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
const resolved = await resolveClaudeVersionEntry(path.join(versionsDir, entry));
|
|
585
|
+
if (resolved) {
|
|
586
|
+
return resolved;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
catch {
|
|
591
|
+
// continue with other install layouts
|
|
592
|
+
}
|
|
593
|
+
return null;
|
|
594
|
+
};
|
|
539
595
|
const getWrapperInstallPaths = async (claudeCommandPath) => {
|
|
540
596
|
const directory = path.dirname(claudeCommandPath);
|
|
541
597
|
const existingNative = await findExistingClaudeNativeInDirectory(directory);
|
|
@@ -656,6 +712,10 @@ const ensurePersistentCodexRouting = async () => {
|
|
|
656
712
|
return "installed";
|
|
657
713
|
};
|
|
658
714
|
const resolveClaudeBinary = async () => {
|
|
715
|
+
const latestManagedVersion = await resolveLatestClaudeManagedVersion();
|
|
716
|
+
if (latestManagedVersion) {
|
|
717
|
+
return latestManagedVersion;
|
|
718
|
+
}
|
|
659
719
|
for (const name of getClaudeNativeNames()) {
|
|
660
720
|
const nativeInPath = await findExecutableInPath(name);
|
|
661
721
|
if (nativeInPath) {
|
|
@@ -674,27 +734,10 @@ const resolveClaudeBinary = async () => {
|
|
|
674
734
|
path.join(os.homedir(), ".local", "bin", "claude"),
|
|
675
735
|
];
|
|
676
736
|
for (const candidate of homeBinCandidates) {
|
|
677
|
-
if (await isExecutable(candidate)) {
|
|
737
|
+
if ((await isExecutable(candidate)) && !(await isManagedClaudeWrapper(candidate))) {
|
|
678
738
|
return candidate;
|
|
679
739
|
}
|
|
680
740
|
}
|
|
681
|
-
const versionsDir = path.join(os.homedir(), ".local", "share", "claude", "versions");
|
|
682
|
-
try {
|
|
683
|
-
const entries = await fs.readdir(versionsDir);
|
|
684
|
-
const latest = entries.sort((left, right) => left.localeCompare(right, undefined, {
|
|
685
|
-
numeric: true,
|
|
686
|
-
sensitivity: "base",
|
|
687
|
-
})).at(-1);
|
|
688
|
-
if (latest) {
|
|
689
|
-
const resolved = await resolveClaudeVersionEntry(path.join(versionsDir, latest));
|
|
690
|
-
if (resolved) {
|
|
691
|
-
return resolved;
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
catch {
|
|
696
|
-
// continue
|
|
697
|
-
}
|
|
698
741
|
for (const name of getClaudeCommandNames()) {
|
|
699
742
|
const claudeInPath = await findExecutableInPath(name);
|
|
700
743
|
if (claudeInPath && !(await isManagedClaudeWrapper(claudeInPath))) {
|
package/dist/config.js
CHANGED
|
@@ -7,6 +7,12 @@ const DEFAULT_PROVIDER = "nvidia";
|
|
|
7
7
|
const DEFAULT_NVIDIA_MODEL = "moonshotai/kimi-k2.5";
|
|
8
8
|
const DEFAULT_OPENROUTER_MODEL = "anthropic/claude-sonnet-4.6";
|
|
9
9
|
const DEFAULT_MAX_REQUESTS_PER_MINUTE = 40;
|
|
10
|
+
const NVIDIA_MODEL_ALIASES = {
|
|
11
|
+
"deepseek/deepseek-v4-pro": "deepseek-ai/deepseek-v4-flash",
|
|
12
|
+
"deepseek-ai/deepseek-v4-pro": "deepseek-ai/deepseek-v4-flash",
|
|
13
|
+
"deepseek-ai/deepseek-v3.2": "deepseek-ai/deepseek-v4-flash",
|
|
14
|
+
};
|
|
15
|
+
const normalizeNvidiaModel = (model) => NVIDIA_MODEL_ALIASES[model] || model;
|
|
10
16
|
const getEnvNumber = (name) => {
|
|
11
17
|
const raw = process.env[name];
|
|
12
18
|
if (!raw) {
|
|
@@ -61,7 +67,7 @@ const withDefaults = (config) => {
|
|
|
61
67
|
return {
|
|
62
68
|
provider: config.provider === "openrouter" ? "openrouter" : DEFAULT_PROVIDER,
|
|
63
69
|
nvidiaApiKey: config.nvidiaApiKey?.trim() || legacyApiKey,
|
|
64
|
-
nvidiaModel: config.nvidiaModel?.trim() || legacyModel,
|
|
70
|
+
nvidiaModel: normalizeNvidiaModel(config.nvidiaModel?.trim() || legacyModel),
|
|
65
71
|
openrouterApiKey: config.openrouterApiKey?.trim() || "",
|
|
66
72
|
openrouterModel: config.openrouterModel?.trim() || DEFAULT_OPENROUTER_MODEL,
|
|
67
73
|
proxyPort: Number.isInteger(config.proxyPort) && config.proxyPort > 0
|
package/dist/models.js
CHANGED
|
@@ -15,9 +15,9 @@ export const NVIDIA_CURATED_MODELS = [
|
|
|
15
15
|
description: "General purpose reasoning model with code capability.",
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
|
-
id: "deepseek-ai/deepseek-
|
|
19
|
-
label: "DeepSeek
|
|
20
|
-
description: "
|
|
18
|
+
id: "deepseek-ai/deepseek-v4-flash",
|
|
19
|
+
label: "DeepSeek V4 Flash",
|
|
20
|
+
description: "Responsive DeepSeek V4-family model.",
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
id: "mistralai/codestral-22b-instruct-v0.1",
|
|
@@ -30,6 +30,36 @@ export const NVIDIA_CURATED_MODELS = [
|
|
|
30
30
|
description: "Smaller coding-focused Qwen model.",
|
|
31
31
|
},
|
|
32
32
|
];
|
|
33
|
+
const NVIDIA_MODEL_FAMILIES = [
|
|
34
|
+
{
|
|
35
|
+
name: "Kimi",
|
|
36
|
+
labelPrefix: "Kimi",
|
|
37
|
+
description: "Latest available Kimi model from NVIDIA.",
|
|
38
|
+
match: /^moonshotai\/kimi/i,
|
|
39
|
+
prefer: [/k2\.5/i, /thinking/i, /instruct/i],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "DeepSeek",
|
|
43
|
+
labelPrefix: "DeepSeek",
|
|
44
|
+
description: "Latest available DeepSeek model from NVIDIA.",
|
|
45
|
+
match: /^deepseek-ai\/deepseek/i,
|
|
46
|
+
prefer: [/v4-flash/i, /v4-pro/i, /v4/i, /v3\.2/i, /coder/i],
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "GLM",
|
|
50
|
+
labelPrefix: "GLM",
|
|
51
|
+
description: "Latest available GLM model from NVIDIA.",
|
|
52
|
+
match: /^z-ai\/glm/i,
|
|
53
|
+
prefer: [/5\.1/i, /5/i, /4\.7/i],
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: "Qwen",
|
|
57
|
+
labelPrefix: "Qwen",
|
|
58
|
+
description: "Latest available Qwen coding model from NVIDIA.",
|
|
59
|
+
match: /^qwen\/qwen/i,
|
|
60
|
+
prefer: [/qwen3-coder/i, /qwen3\.5/i, /qwen3-next/i, /qwen3/i, /qwen2\.5-coder/i],
|
|
61
|
+
},
|
|
62
|
+
];
|
|
33
63
|
export const OPENROUTER_CURATED_MODELS = [
|
|
34
64
|
{
|
|
35
65
|
id: "qwen/qwen3.6-plus-preview:free",
|
|
@@ -71,14 +101,87 @@ export const fetchAvailableModelIds = async (apiKey) => {
|
|
|
71
101
|
}
|
|
72
102
|
return ids;
|
|
73
103
|
};
|
|
104
|
+
const formatModelNameToken = (part) => {
|
|
105
|
+
const normalized = part.toLowerCase();
|
|
106
|
+
const brandNames = {
|
|
107
|
+
deepseek: "DeepSeek",
|
|
108
|
+
glm: "GLM",
|
|
109
|
+
kimi: "Kimi",
|
|
110
|
+
qwen: "Qwen",
|
|
111
|
+
};
|
|
112
|
+
if (brandNames[normalized]) {
|
|
113
|
+
return brandNames[normalized];
|
|
114
|
+
}
|
|
115
|
+
if (/^[vk]\d/i.test(part) || /^\d+b$/i.test(part) || /^a\d+b$/i.test(part)) {
|
|
116
|
+
return part.toUpperCase();
|
|
117
|
+
}
|
|
118
|
+
return part.charAt(0).toUpperCase() + part.slice(1);
|
|
119
|
+
};
|
|
120
|
+
const titleCaseModelPart = (value) => value
|
|
121
|
+
.split(/[-_]/)
|
|
122
|
+
.filter(Boolean)
|
|
123
|
+
.map(formatModelNameToken)
|
|
124
|
+
.join(" ");
|
|
125
|
+
const formatDynamicLabel = (family, id) => {
|
|
126
|
+
const modelName = id.split("/").at(-1) || id;
|
|
127
|
+
return `${family.labelPrefix}: ${titleCaseModelPart(modelName)}`;
|
|
128
|
+
};
|
|
129
|
+
const getVersionScore = (id) => {
|
|
130
|
+
const versionNumbers = [...id.matchAll(/\d+(?:\.\d+)?/g)]
|
|
131
|
+
.map((match) => Number(match[0]))
|
|
132
|
+
.filter((value) => Number.isFinite(value));
|
|
133
|
+
if (versionNumbers.length === 0) {
|
|
134
|
+
return 0;
|
|
135
|
+
}
|
|
136
|
+
return Math.max(...versionNumbers);
|
|
137
|
+
};
|
|
138
|
+
const scoreFamilyModel = (family, id) => {
|
|
139
|
+
let score = getVersionScore(id);
|
|
140
|
+
family.prefer.forEach((pattern, index) => {
|
|
141
|
+
if (pattern.test(id)) {
|
|
142
|
+
score += (family.prefer.length - index) * 1000;
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
if (/preview|beta|experimental/i.test(id)) {
|
|
146
|
+
score -= 10;
|
|
147
|
+
}
|
|
148
|
+
return score;
|
|
149
|
+
};
|
|
150
|
+
const pickFamilyModel = (family, ids) => {
|
|
151
|
+
const candidates = ids.filter((id) => family.match.test(id));
|
|
152
|
+
if (candidates.length === 0) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
const [best] = candidates.sort((left, right) => {
|
|
156
|
+
const scoreDelta = scoreFamilyModel(family, right) - scoreFamilyModel(family, left);
|
|
157
|
+
return scoreDelta || right.localeCompare(left, undefined, { numeric: true });
|
|
158
|
+
});
|
|
159
|
+
if (!best) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
id: best,
|
|
164
|
+
label: formatDynamicLabel(family, best),
|
|
165
|
+
description: family.description,
|
|
166
|
+
};
|
|
167
|
+
};
|
|
168
|
+
const getDynamicNvidiaModels = (available) => {
|
|
169
|
+
const ids = [...available];
|
|
170
|
+
const picked = NVIDIA_MODEL_FAMILIES
|
|
171
|
+
.map((family) => pickFamilyModel(family, ids))
|
|
172
|
+
.filter((model) => Boolean(model));
|
|
173
|
+
const seen = new Set(picked.map((model) => model.id));
|
|
174
|
+
const fallback = NVIDIA_CURATED_MODELS.filter((model) => available.has(model.id) && !seen.has(model.id));
|
|
175
|
+
return [...picked, ...fallback];
|
|
176
|
+
};
|
|
74
177
|
export const getRecommendedModels = async (provider, apiKey) => {
|
|
75
178
|
if (provider === "openrouter") {
|
|
76
179
|
return OPENROUTER_CURATED_MODELS;
|
|
77
180
|
}
|
|
78
181
|
try {
|
|
79
182
|
const available = await fetchAvailableModelIds(apiKey);
|
|
80
|
-
const
|
|
81
|
-
return
|
|
183
|
+
const dynamic = getDynamicNvidiaModels(available);
|
|
184
|
+
return dynamic.length > 0 ? dynamic : NVIDIA_CURATED_MODELS;
|
|
82
185
|
}
|
|
83
186
|
catch {
|
|
84
187
|
return NVIDIA_CURATED_MODELS;
|
package/dist/proxy.js
CHANGED
|
@@ -6,12 +6,33 @@ const NVIDIA_URL = "https://integrate.api.nvidia.com/v1/chat/completions";
|
|
|
6
6
|
const OPENROUTER_URL = "https://openrouter.ai/api/v1/chat/completions";
|
|
7
7
|
const DEFAULT_RETRY_DELAY_MS = 2_000;
|
|
8
8
|
const MAX_NVIDIA_RETRIES = 3;
|
|
9
|
+
const UPSTREAM_TIMEOUT_MS = 60_000;
|
|
10
|
+
const PROXY_PROTOCOL_VERSION = 2;
|
|
9
11
|
const sleep = async (ms) => {
|
|
10
12
|
if (ms <= 0) {
|
|
11
13
|
return;
|
|
12
14
|
}
|
|
13
15
|
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
14
16
|
};
|
|
17
|
+
const fetchWithTimeout = async (input, init) => {
|
|
18
|
+
const controller = new AbortController();
|
|
19
|
+
const timeout = setTimeout(() => controller.abort(), UPSTREAM_TIMEOUT_MS);
|
|
20
|
+
try {
|
|
21
|
+
return await fetch(input, {
|
|
22
|
+
...init,
|
|
23
|
+
signal: controller.signal,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
if (error.name === "AbortError") {
|
|
28
|
+
throw new Error(`Upstream API timed out after ${UPSTREAM_TIMEOUT_MS / 1000}s`);
|
|
29
|
+
}
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
clearTimeout(timeout);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
15
36
|
const parseRetryAfterMs = (value) => {
|
|
16
37
|
if (!value) {
|
|
17
38
|
return null;
|
|
@@ -415,14 +436,14 @@ const callNvidia = async (config, scheduleRequest, payload) => {
|
|
|
415
436
|
if (toolChoice) {
|
|
416
437
|
requestBody.tool_choice = toolChoice;
|
|
417
438
|
}
|
|
418
|
-
if (config.
|
|
439
|
+
if (config.provider === "nvidia") {
|
|
419
440
|
requestBody.chat_template_kwargs = {
|
|
420
|
-
thinking:
|
|
441
|
+
thinking: config.thinking,
|
|
421
442
|
};
|
|
422
443
|
}
|
|
423
444
|
const invoke = async () => {
|
|
424
445
|
for (let attempt = 0; attempt <= MAX_NVIDIA_RETRIES; attempt += 1) {
|
|
425
|
-
const response = await
|
|
446
|
+
const response = await fetchWithTimeout(NVIDIA_URL, {
|
|
426
447
|
method: "POST",
|
|
427
448
|
headers: {
|
|
428
449
|
Authorization: `Bearer ${config.nvidiaApiKey}`,
|
|
@@ -654,7 +675,7 @@ const callChatCompletions = async (config, scheduleRequest, body) => {
|
|
|
654
675
|
const apiKey = getActiveApiKey(config);
|
|
655
676
|
const invoke = async () => {
|
|
656
677
|
for (let attempt = 0; attempt <= MAX_NVIDIA_RETRIES; attempt += 1) {
|
|
657
|
-
const resp = await
|
|
678
|
+
const resp = await fetchWithTimeout(upstreamUrl, {
|
|
658
679
|
method: "POST",
|
|
659
680
|
headers: {
|
|
660
681
|
Authorization: `Bearer ${apiKey}`,
|
|
@@ -691,7 +712,9 @@ export const createProxyServer = (config) => {
|
|
|
691
712
|
if (url.pathname === "/health") {
|
|
692
713
|
sendJson(response, 200, {
|
|
693
714
|
ok: true,
|
|
694
|
-
|
|
715
|
+
proxyProtocolVersion: PROXY_PROTOCOL_VERSION,
|
|
716
|
+
provider: config.provider,
|
|
717
|
+
model: getActiveModel(config),
|
|
695
718
|
port: config.proxyPort,
|
|
696
719
|
thinking: config.thinking,
|
|
697
720
|
maxRequestsPerMinute: config.maxRequestsPerMinute,
|
|
@@ -872,6 +895,11 @@ export const createProxyServer = (config) => {
|
|
|
872
895
|
max_tokens: payload.max_output_tokens ?? 16_384,
|
|
873
896
|
stream: false,
|
|
874
897
|
};
|
|
898
|
+
if (config.provider === "nvidia") {
|
|
899
|
+
chatBody.chat_template_kwargs = {
|
|
900
|
+
thinking: config.thinking,
|
|
901
|
+
};
|
|
902
|
+
}
|
|
875
903
|
if (typeof payload.temperature === "number") {
|
|
876
904
|
chatBody.temperature = payload.temperature;
|
|
877
905
|
}
|